]> Git [git.vados.ru] :: Repos - Mikrotiks/Mikrotiks.git/commitdiff
Autocommit in repo: , generated by owner: mikro_bak, in 08:40:02 13.03.2026.
authorvados-dev <vados@vados.ru>
Fri, 13 Mar 2026 05:40:02 +0000 (08:40 +0300)
committervados-dev <vados@vados.ru>
Fri, 13 Mar 2026 05:40:02 +0000 (08:40 +0300)
bin/ros-deploy.sh [new file with mode: 0755]
bin/ros-diff.sh

diff --git a/bin/ros-deploy.sh b/bin/ros-deploy.sh
new file mode 100755 (executable)
index 0000000..1b203c8
--- /dev/null
@@ -0,0 +1,328 @@
+#!/bin/bash
+#
+# ros-deploy.sh - Bulk RouterOS Script Deployment Tool
+# Version: 1.2.1 (2025-06-26)
+#
+# A powerful and flexible tool for deploying RouterOS scripts to multiple
+# MikroTik devices simultaneously via SSH. It supports both single-host
+# deployment and batch deployment from a hosts file.
+#
+# Features:
+# - Deploy scripts to a single host or a list of hosts from a file
+# - Securely uploads and executes scripts using SCP and SSH
+# - Supports user, host, and port specification ([user@]host[:port])
+# - Automatic cleanup of temporary script files on the remote device
+# - Configurable connection timeout
+# - Detailed summary of successful and failed deployments
+# - Supports SSH key-based authentication for passwordless execution
+#
+# Usage: ./ros-deploy.sh [OPTIONS] (-h HOST | -H HOSTS_FILE) -s SCRIPT_FILE [-i IDENTITY_FILE]
+#
+# Author: Nikita Tarikin <nikita@tarikin.com>
+# GitHub: https://github.com/tarikin/ros-deploy
+# License: MIT
+#
+# Copyright (c) 2025 Nikita Tarikin
+#
+set -euo pipefail
+
+# Default values
+DEFAULT_CONNECT_TIMEOUT=5  # Default connection timeout in seconds
+NO_COLOR=false  # Default color output enabled
+
+# Color codes (only used when output is a terminal and NO_COLOR is false)
+if [ -t 1 ] && ! $NO_COLOR; then
+    COLOR_RESET='\033[0m'
+    COLOR_BOLD='\033[1m'
+    COLOR_RED='\033[1;31m'
+    COLOR_GREEN='\033[1;32m'
+    COLOR_YELLOW='\033[1;33m'
+    COLOR_BLUE='\033[1;34m'
+    COLOR_CYAN='\033[1;36m'
+else
+    COLOR_RESET='' COLOR_BOLD='' COLOR_RED='' COLOR_GREEN='' COLOR_YELLOW='' COLOR_BLUE='' COLOR_CYAN=''
+fi
+
+# Helper functions for colored output
+info() {
+    echo -e "${COLOR_BLUE}ℹ $*${COLOR_RESET}"
+}
+
+success() {
+    echo -e "${COLOR_GREEN}✅ $*${COLOR_RESET}"
+}
+
+error() {
+    echo -e "${COLOR_RED}❌ Error: $*${COLOR_RESET}" >&2
+}
+
+warning() {
+    echo -e "${COLOR_YELLOW}⚠ $*${COLOR_RESET}" >&2
+}
+
+section() {
+    echo -e "\n${COLOR_CYAN}=== $* ===${COLOR_RESET}"
+}
+
+# Help message - uses plain echo to avoid color codes in output
+show_help() {
+    cat << 'EOF'
+Deploy RouterOS scripts to one or more devices
+
+Usage: ros-deploy [OPTIONS] (-h HOST | -H HOSTS_FILE) -s SCRIPT_FILE
+
+Options:
+      --help            Show this help message and exit
+  -h, --host HOST        Single RouterOS device to deploy to (format: [user@]hostname[:port])
+  -H, --hosts FILE       File containing list of RouterOS devices (one per line, format: [user@]hostname[:port])
+  -s, --script FILE     RouterOS script file to execute
+  -t, --timeout SECONDS Connection timeout in seconds (default: 5)
+  -i, --identity FILE  SSH private key file to use for authentication
+      --no-color       Disable colored output
+
+Examples:
+  ros-deploy -H routers.txt -s config.rsc -t 10
+  ros-deploy -h admin@router.local -s config.rsc --no-color
+EOF
+    exit 0
+}
+
+# Parse command line arguments
+HOSTS_FILE=""
+SINGLE_HOST=""
+SCRIPT_FILE=""
+CONNECT_TIMEOUT="$DEFAULT_CONNECT_TIMEOUT"
+IDENTITY_FILE=""
+NO_COLOR=false
+
+while [[ $# -gt 0 ]]; do
+    case $1 in
+        --help)
+            show_help
+            ;;
+        --no-color)
+            NO_COLOR=true
+            # Re-initialize colors if needed
+            if $NO_COLOR; then
+                COLOR_RESET='' COLOR_BOLD='' COLOR_RED='' COLOR_GREEN='' COLOR_YELLOW='' COLOR_BLUE='' COLOR_CYAN=''
+            fi
+            shift
+            ;;
+        -h|--host)
+            if [ -z "$2" ] || [[ "$2" == -* ]]; then
+                echo "Error: Missing host argument for $1" >&2
+                show_help
+                exit 1
+            fi
+            SINGLE_HOST="$2"
+            shift 2
+            ;;
+        -H|--hosts)
+            if [ -z "$2" ] || [[ "$2" == -* ]]; then
+                echo "Error: Missing hosts file argument for $1" >&2
+                show_help
+                exit 1
+            fi
+            HOSTS_FILE="$2"
+            shift 2
+            ;;
+        -s|--script)
+            if [ -z "$2" ] || [[ "$2" == -* ]]; then
+                echo "Error: Missing script file argument for $1" >&2
+                show_help
+                exit 1
+            fi
+            SCRIPT_FILE="$2"
+            shift 2
+            ;;
+        -t|--timeout)
+            if [ -z "$2" ] || [[ "$2" == -* ]]; then
+                echo "Error: Missing timeout value for $1" >&2
+                show_help
+                exit 1
+            fi
+            # Validate timeout is a positive number
+            if ! [[ "$2" =~ ^[0-9]+$ ]] || [ "$2" -eq 0 ]; then
+                echo "Error: Timeout must be a positive integer" >&2
+                exit 1
+            fi
+            CONNECT_TIMEOUT="$2"
+            shift 2
+            ;;
+        -i|--identity-file)
+            if [ -z "$2" ] || [[ "$2" == -* ]]; then
+                echo "Error: Missing identity file argument for $1" >&2
+                show_help
+                exit 1
+            fi
+            IDENTITY_FILE="$2"
+            shift 2
+            ;;
+        *)
+            echo "Error: Unknown option or missing argument: $1" >&2
+            show_help
+            exit 1
+            ;;
+    esac
+done
+
+# Validate required parameters
+if { [ -z "$HOSTS_FILE" ] && [ -z "$SINGLE_HOST" ]; } || [ -z "$SCRIPT_FILE" ]; then
+    echo "Error: You must specify either --host or --hosts, and --script" >&2
+    show_help
+    exit 1
+fi
+
+TEMP_SCRIPT_NAME="$(basename "$SCRIPT_FILE")"
+
+# Check if files exist
+if [ -n "$HOSTS_FILE" ] && [ ! -f "$HOSTS_FILE" ]; then
+    error "Hosts file '$HOSTS_FILE' not found"
+    echo "Please create a file with a list of routers, one per line, in format: [user@]hostname[:port]" >&2
+    exit 1
+fi
+
+if [ -n "$IDENTITY_FILE" ] && [ ! -f "$IDENTITY_FILE" ]; then
+    error "Identity file '$IDENTITY_FILE' not found"
+    exit 1
+fi
+
+if [ ! -f "$SCRIPT_FILE" ]; then
+    error "RouterOS script file '$SCRIPT_FILE' not found"
+    echo "Please specify a valid RouterOS script file to execute" >&2
+    exit 1
+fi
+
+# Function to execute RouterOS script
+execute_routeros_script() {
+    local host="$1"
+    local user="admin"  # default user
+    local port="22"     # default SSH/SCP port (RouterOS uses the same port for both)
+    local target
+    
+    # Extract user if specified
+    if [[ "$host" == *"@"* ]]; then
+        user="${host%%@*}"
+        host="${host#*@}"
+    fi
+    
+    # Extract port if specified
+    # Extract port if specified (format: hostname:port or user@hostname:port)
+    if [[ "$host" == *":"* ]]; then
+        port="${host##*:}"
+        host="${host%:*}"
+    fi
+    
+    target="$user@$host"
+    
+    section "[$(date +'%Y-%m-%d %H:%M:%S')] Processing $target (port $port)"
+    
+    # Build base SSH/SCP options
+    local ssh_opts=("-o BatchMode=yes" "-o ConnectTimeout=$CONNECT_TIMEOUT" "-o StrictHostKeyChecking=accept-new")
+    if [ -n "$IDENTITY_FILE" ]; then
+        ssh_opts+=("-i $IDENTITY_FILE")
+    fi
+
+    # 1. First, copy the script to the router using SCP
+    info "Uploading script to router..."
+    # shellcheck disable=SC2086
+    if scp ${ssh_opts[*]} -P "$port" "$SCRIPT_FILE" "$target:$TEMP_SCRIPT_NAME"; then
+        
+        info "Script uploaded successfully, executing..."
+        
+        # 2. Only execute SSH if SCP was successful
+        # shellcheck disable=SC2086
+        if ssh ${ssh_opts[*]} -p "$port" "$target" "/import verbose=no $TEMP_SCRIPT_NAME; /file/remove $TEMP_SCRIPT_NAME"; then
+            success "Successfully executed script on $target"
+            return 0
+        else
+            error "Failed to execute script on $target"
+            return 1
+        fi
+    else
+        error "Failed to upload script to $target"
+        return 1
+    fi
+}
+
+# Initialize tracking variables
+FAILED_HOSTS=()
+TOTAL=0
+SUCCESS=0
+
+# Process hosts
+section "Starting RouterOS deployment"
+if [ -n "$SINGLE_HOST" ]; then
+    info "Single host:   $SINGLE_HOST"
+fi
+if [ -n "$HOSTS_FILE" ]; then
+    info "Hosts file:    $HOSTS_FILE"
+fi
+info "Script file:   $SCRIPT_FILE"
+info "Connect timeout: $CONNECT_TIMEOUT seconds"
+info "SSH Key:       $(ssh-add -l 2>/dev/null || echo "No SSH key loaded in agent")"
+echo -e "${COLOR_YELLOW}----------------------------------------${COLOR_RESET}"
+
+# Process single host if specified
+if [ -n "$SINGLE_HOST" ]; then
+    ((TOTAL++))
+    if execute_routeros_script "$SINGLE_HOST"; then
+        ((SUCCESS++))
+    else
+        FAILED_HOSTS+=("$SINGLE_HOST")
+    fi
+fi
+
+# Process hosts file if specified
+if [ -n "$HOSTS_FILE" ]; then
+    # Read hosts file into an array, skipping comments and empty lines
+    HOSTS=()
+    while IFS= read -r line; do
+        # Remove comments and trim whitespace
+        line="${line%%#*}"  # Remove comments
+        line="${line##*([[:space:]])}"  # Remove leading whitespace
+        line="${line%%*([[:space:]])}"  # Remove trailing whitespace
+        
+        # Skip empty lines
+        [ -n "$line" ] && HOSTS+=("$line")
+    done < "$HOSTS_FILE"
+
+    if [ ${#HOSTS[@]} -eq 0 ]; then
+        error "${COLOR_RED}No valid hosts found in $HOSTS_FILE${COLOR_RESET}"
+        exit 1
+    fi
+
+    success "${COLOR_GREEN}Found ${#HOSTS[@]} host(s) in file${COLOR_RESET}"
+
+    # Process each host from the file
+    for host in "${HOSTS[@]}"; do
+        ((TOTAL++))
+        if execute_routeros_script "$host"; then
+            ((SUCCESS++))
+        else
+            FAILED_HOSTS+=("$host")
+        fi
+    done
+fi
+
+# Print summary
+section "Deployment Summary"
+info "Total hosts:    $TOTAL"
+if [ $SUCCESS -gt 0 ]; then
+    success "Successful:     $SUCCESS"
+else
+    info "Successful:     $SUCCESS"
+fi
+
+if [ ${#FAILED_HOSTS[@]} -gt 0 ]; then
+    error "Failed:         ${#FAILED_HOSTS[@]}"
+    echo -e "\n${COLOR_RED}Failed hosts:${COLOR_RESET}"
+    printf '  - %s\n' "${FAILED_HOSTS[@]}"
+    exit 1
+else
+    success "Failed:         ${#FAILED_HOSTS[@]}"
+fi
+
+echo
+success "All deployments completed successfully!"
+exit 0
index f7075f90982b14f0b1d636bdfe13b2638be3ca36..8d183eced10a7d6f9c7967fc86ae777f465898cb 100755 (executable)
@@ -92,22 +92,22 @@ if [ -t 1 ] && $DEBUG_OUT; then
     green=$(tput setaf 2)
     bg_green=$(tput setab 2)
     yellow=$(tput setaf 3)
-    blue=$(tput setaf 4)
+    blue='\033[1;34m' #$(tput setaf 4)
     magenta=$(tput setaf 5)
     cyan=$(tput setaf 6)
     white=$(tput setaf 7)
     toend=$(tput hpa $(tput cols))$(tput cub 6)
 else
-    reset='' bold='' red='' green='' yellow='' blue='' magenta='' cyan='' white='' toend=''
+    reset='' bold='' red='' green='' bg_green='' yellow='' blue='' magenta='' cyan='' white='' toend=''
 fi
 help() {
-    echo -e "\n${white}❓  $*${reset}"
+    echo -e "\n${white}❓ $*${reset}"
 }
 info() {
-    echo -e "\n${cyan}🌀  $*${reset}"
+    echo -e "\n${blue}i $*${reset}"
 }
 success() {
-    echo -e "\n${green}✅  $*${reset}"
+    echo -e "\n${green}✅ $*${reset}"
 }
 error() {
     echo -e "\n${red}❌ $*${reset}" >&2
@@ -137,11 +137,6 @@ spinstr()
 #  echo -ne "\\r[✅]\\n"
 tput cnorm --
 }
-# Source - https://stackoverflow.com/a/34392382
-# Posted by fipsbox, modified by community. See post 'Timeline' for change history
-# Retrieved 2026-03-12, License - CC BY-SA 4.0
-
-
 #sleep 10 &
 #spinstr $!
 #exit 0