ktbyers / netmiko

Multi-vendor library to simplify Paramiko SSH connections to network devices
MIT License
3.62k stars 1.31k forks source link

Timed-out reading channel, data not available. (Mikrotik) #2804

Open kghost310 opened 2 years ago

kghost310 commented 2 years ago

Im getting a timed-out error.

here is my code. can anyone help?

#!/usr/bin/env python
import time
from netmiko import ConnectHandler
from netmiko.ssh_exception import NetmikoTimeoutException
import logging

logging.basicConfig(filename='test.log', level=logging.DEBUG)
logger = logging.getLogger("netmiko")

MTR01 = {
    'device_type': 'mikrotik_routeros',
    'ip': '192.168.68.63',
    'port': 22,
    'username': 'admin',
    'password': ''
}

with open('config') as f:
    lines = f.read().splitlines()
print(lines)

all_devices = [MTR01]
for devices in all_devices:
    print(f'Connecting to {devices["ip"]}')
    try:
        connection = ConnectHandler(**MTR01)
        connection.send_config_set(lines, enter_config_mode=True, cmd_verify=True, delay_factor=40, max_loops=250, strip_prompt=True)
        print()
        connection.disconnect()
    except NetmikoTimeoutException as e:
        print(f"Exception has occurred:\n{e}")
        continue

    print(f'These rules have been installed on {devices["ip"]} ')
    net_connect = ConnectHandler(**devices)
    output1 = net_connect.send_command()
    print(output1)
    time.sleep(2)
ktbyers commented 2 years ago

Why do you connect twice to the same device i.e. you have two ConnectHandler calls above?

Also can you get rid of you try/except statement and then include the full exception stack trace here?

kghost310 commented 2 years ago

Im new to all this so i saw some code in multiple places and just modified it to what I thought would work. The Try/Except i read should have helped with the timing error.

Could you guide me with an example of what i should try to change please.

kghost310 commented 2 years ago

latest edits and still get an error.

#!/usr/bin/env python
import time
from netmiko import ConnectHandler
from netmiko.ssh_exception import NetmikoTimeoutException
import logging

logging.basicConfig(filename='test.log', level=logging.DEBUG)
logger = logging.getLogger("netmiko")

MTR01 = {
    'device_type': 'mikrotik_routeros',
    'ip': '192.168.68.63',
    'port': 22,
    'username': 'admin',
    'password': ''
}

all_devices = [MTR01]
for devices in all_devices:
    print(f'Connecting to {devices["ip"]}')

with open('config') as f:
    lines = f.read().splitlines()
print(lines)

connection = ConnectHandler(**MTR01)
connection.send_config_set(lines, enter_config_mode=True, cmd_verify=True, delay_factor=40, max_loops=250,
                           strip_prompt=True)
print()
connection.disconnect()

print(f'These rules have been installed on {devices["ip"]} ')
output1 = net_connect.send_command()
print(output1)
time.sleep(2)

This is my output please help if you can.

Traceback (most recent call last): File "/Users/Kshanklin/PycharmProjects/Mikrotik/v2/main.py", line 27, in connection.send_config_set(lines, enter_config_mode=True, cmd_verify=True, delay_factor=40, max_loops=250, File "/Users/Kshanklin/PycharmProjects/Mikrotik/v2/venv/lib/python3.8/site-packages/netmiko/base_connection.py", line 2171, in send_config_set output += self.read_until_pattern(pattern=pattern, re_flags=re.M) File "/Users/Kshanklin/PycharmProjects/Mikrotik/v2/venv/lib/python3.8/site-packages/netmiko/base_connection.py", line 651, in read_until_pattern raise ReadTimeout(msg) netmiko.exceptions.ReadTimeout:

Pattern not detected: '(?:\[admin@MikroTik\].$|#.$)' in output.

Things you might try to fix this:

  1. Adjust the regex pattern to better identify the terminating string. Note, in many situations the pattern is automatically based on the network device's prompt.
  2. Increase the read_timeout to a larger value.
ktbyers commented 2 years ago

@kghost310 Can you show me what is contained in the variable lines?

Also which version of Netmiko are you using?

kghost310 commented 2 years ago

@ktbyers lines opens the 'config' file listed below, I believe I am on the newest version of Netmiko, I recently installed it I tried netmiko.version but it didnt tell me anything.

:global localidentity ([/interface ethernet get [find default-name=ether1] mac-address]); :delay 5s; :global EventClass; :global APMAC; :global Name; :global GlobalNat; :global ClassArray { "00:0C:29:D0:80:C5"={ "Class"="Subnet1" ; "APMAC"="EC:8C:A2:27:D8:C0" ; "ID"="SHANKLIN" ; "NAT"="true" } ; "B8:69:F4:5B:52:BF"={ "Class"="Subnet1" ; "APMAC"="EC:8E:A2:28:D8:C0" ; "ID"="LVRM" ; "NAT"="true" } ; "6C:3A:6B:2D:38:61"={ "Class"="Subnet1" ; "APMAC"="EC:8E:A2:28:D8:C0" ; "ID"="BSMNT" ; "NAT"="true" } ; "B8:69:E4:58:57:59"={ "Class"="Subnet1" ; "APMAC"="EC:8E:A2:28:D8:C0" ; "ID"="ATTAK" ; "NAT"="true" } }; :foreach k,v in=$ClassArray do={ :if ($localidentity = "$k" ) do={ :foreach k2,v2 in=$v do={ :if ($k2 = "Class") do={ :global EventClass $v2 } :if ($k2 = "APMAC") do={ :global APMAC $v2 } :if ($k2 = "ID") do={ :global Name $v2 } :if ($k2 = "NAT") do={ :global GlobalNat $v2 } }; } }; :global EventClass; :global APMAC; :global GlobalNat; :put $Name; :delay 1s; :global ArrayEXE [:execute { :global match false; :global Array { "Subnet1"={ "IP"="10.140.8.1" ; "Mask"="255.255.248.0" ; "CIDR"="21" ; "HIT"="true" } ; "Subnet2"={ "IP"="10.140.16.1" ; "Mask"="255.255.248.0" ; "CIDR"="21" ; "HIT"="true" } }; :foreach k,v in=$Array do={ :if ($EventClass = "$k" ) do={ :foreach k2,v2 in=$v do={ :if ( $k2 = "IP" ) do={ :global IP $v2 } :if ( $k2 = "Mask" ) do={ :global NetMask $v2 } :if ( $k2 = "CIDR" ) do={ :global CIDRNetMask $v2 } :if ( $k2 = "HIT" ) do={ :global match $v2 } }; }; }; }]; :global IP; :put $IP; :global NetMask; :put $NetMask; :global CIDRNetMask; :put $CIDRNetMask; :global match; :put $match; :delay 1s; :global Variables [:execute { :if ($match = false) do={ :global IP 10.140.0.1; :global NetMask 255.255.248.0; :global CIDRNetMask 21; } :global Network ($IP&$NetMask); :global InvertedNetMask (~$NetMask); :global Broadcast ($Network|$InvertedNetMask); :global SN1Len [:len $Network]; :set SN1Len ($SN1Len - 2); :global SN2Len [:len $Broadcast]; :set SN2Len ($SN2Len - 4); :global Subnet1 [:pick $Network 0 $SN1Len]; :global Subnet2 [:pick $Broadcast 0 $SN2Len]; :global DHCPPoolRanges ($Subnet1 . ".48-" . $Subnet2 . ".254"); :global APIPAddress ($Subnet1 . ".5"); /system script environment remove "ClassArray"; /system script environment remove "Array"; /system script environment remove "Variables"; /system script environment remove "ArrayEXE"; /system script environment remove "InvertedNetMask"; /system script environment remove "SN1Len"; /system script environment remove "Subnet2"; /system script environment remove "SN2Len"; /system script environment remove "Broadcast"; }];

kghost310 commented 2 years ago

@ktbyers was that the right information you were looking for?

ktbyers commented 2 years ago

@kghost310 It looks like you are embedding TCL inside of your send_config_set call? There is a good chance that is not going to work without special handling on your side.

Does it work with just simplified configuration changes i.e. if you just send a few lines of config changes with no TCL does it work?

kghost310 commented 2 years ago

@kbirkeland So I got this to work with a different script it just takes about 5 mins and I need it to go faster and also connect to multiple devices and do it. with that said I started to try to build a new one with less steps and thats where im at now. <maybe if you have a pointer on how to speed up the old script and how to get it to multiple devices ill just keep that one. here is the old script

!/usr/bin/env python

import time from netmiko import ConnectHandler from netmiko.ssh_exception import NetmikoTimeoutException import logging

startTime = time.time()

logging.basicConfig(filename='API0054.log', level=logging.DEBUG) logger = logging.getLogger("netmiko")

MTR01 = { 'device_type': 'mikrotik_routeros', 'ip': '10.10.56.1', 'port': 22, 'username': 'admin', 'password': 'testpassword1' }

net_connect = ConnectHandler(**MTR01) commands1 = open('config','r')

for commands in commands1: output1 = net_connect.send_command(commands, cmd_verify=True) mt_command = commands.rstrip() print(mt_command) print(output1)

commands2 = open('config2','r')

for commands in commands2: output2 = net_connect.send_command(commands, cmd_verify=True) mt_command = commands.rstrip() print(mt_command) print(output2)

executionTime = (time.time() - startTime) print('Execution time in seconds: ' + str(executionTime))

quit()

ktbyers commented 2 years ago

Which version of Netmiko are you using? How many commands are you sending (roughly).

For multiple devices, you should just threading. Probably the easiest way to do this using Nornir (with the Netmiko-Nornir Plugin).

kghost310 commented 2 years ago

I believe the newest version, i sending roughly 400 commands. ill look into Nornir also

ktbyers commented 2 years ago

@kghost310 Are the commands configuration commands, show commands, or something else?

Do you have TCL embedded in them?

kghost310 commented 2 years ago

@ktbyers they are configuration commands, we are setting up DHCP, firewall rules, etc... on Mikrotik devices. Im not sure if we do. I will look into that.