Asyncio RuntimeError: readuntil() called while another coroutine is already waiting for incoming data - python-asyncio

Using python3.6.8:
I'm attempting to script the initial configuration of network devices on boot. My script opens telnet connection on "ip_addr:port". Once connected, script stimulates the network device it's connecting to with "\n\n" (simulating two 'Enter' input from an admin).
connection = asyncio.open_connection(
ip_addr,
port,
)
try:
reader, writer = await asyncio.wait_for(connection, 5)
print(f"successfully connected to {ip_addr}:{port}")
writer.write(b'\n\n\n')
Some devices are already configured and I except " login: " to show up in the read buffer upon entering '\n'. However if the device is not configured yet, " login: " will not show up in the buffer. Therefore I thought I could use wait_for and timeout option to have this cancelled and move on with another reader.readuntil(...) expecting another output.
try:
await asyncio.wait_for(reader.readuntil(b' login: '), 3)
print(f"{ip_addr}:{port} alredy booted")
break
except (asyncio.TimeoutError, OSError):
print('Nope, moving forward')
await reader.readuntil(b'normal setup ?(yes/no)[n]: ')
However this raises a RuntimeError. Reading the documentation I excepted the task to be cancelled if the timeout is reached, so why can't it have another coroutine readuntil() ?

Related

I'm using a 3 hop SSH with netmiko in Python and it does not like switching between the 2nd and 3rd hops

My topology is: Laptop -> 1st Jumphost (my company) -> 2nd jumphost (my clients company) -> Various network devices (my clients network devices).
The network devices are only accessible from the 2nd jumphost, and the 2nd jumphost is only accessible from the 1st jumphost. So I'm using netmiko in Python to achieve this. My code is below.
The 1st block of code SSH's to the 1st jumphost, and then from there SSH's to the 2nd jumphost. This works correctly.
The 2nd block of code then opens a text file containing the hostnames or IP's of the individual network devices that need to be queried. For each host in that file, it SSH's to it, issues the "show version" command and then disconnects from the device (using "exit") so that the session is returned to the 2nd jumphost, ready for the next device in the file.
This works correctly for the very first device, but crashes upon the "output = device.send_command('exit')" line. Netmiko claims that the pattern is not detected. I think I understand why, because netmiko is using the name in the hostname prompt, when this changes back to the 2nd jumphost hostname upon the disconnect it gets confused and throws an error. If this is the case I have 2 questions:
How come it copes OK when moving from the 1st jumphost to the 2nd jumphost AND from the 2nd jumphost to the network device. In both of these cases the hostname prompt also changes...
What's the solution? How can I safely move between the 2nd jumphost and network devices in order to achieve the loop?
from netmiko import ConnectHandler
import time
jump1 = "x.x.x.x"
jump2 = "y.y.y.y"
jump1_username = "myusername"
jump1_password = "mypassword"
jump2_username = "myusername"
jump2_password = "mypassword"
jump_type = "linux"
cmd_jump = "ssh " + jump2_username + "#" + jump2 + "\n"
device = ConnectHandler(device_type=jump_type, ip=jump1, username=jump1_username, password=jump1_password) # ssh to 1st jumphost
output = device.send_command('cat /proc/sys/kernel/hostname') #just shows me that login worked
print(output, flush=True) # just shows me that login worked
device.write_channel(cmd_jump) # enters ssh command for 2nd jumphost
time.sleep(1)
device.write_channel(jump2_password + "\n") # enters password for 2nd jumphost
time.sleep(1)
output = device.send_command('cat /proc/sys/kernel/hostname') #just shows me that second login worked
print(output, flush=True) # just shows me that second login worked
host_list = open(r'C:\device_list.txt','r') # a simple list of IP addresses you want to connect to each one on a new line
for host in host_list: # loop through network devices
host = host.strip()
cmd_device = "ssh " + host
device.write_channel(cmd_device + "\n") # ssh to each device
time.sleep(1)
device.write_channel(jump2_password + "\n") # enter ssh password (credientals are the same as the 2nd jumphost)
time.sleep(1)
output = device.send_command('sh ver') # run show version command
print(output, flush=True)
output = device.send_command('exit') ' disconnect from network device to return to the 2nd jumphost
time.sleep(1)
print(output, flush=True)
Ignore me, I've solved my own problem. It's because I wasn't using the "write_channel" to enter the 'exit' command. Doh!

pexpect timed out before script ends

I am using pexpect to connect to a remote server using ssh.
The following code works but I have to use time.sleep to make a delay.
Especially when I am sending a command to run a script on the remote server.
The script will take up to a minute to run and if I don't use a 60 seconds delay, then the script will end prematurely.
The same issue when I am using sftp to download a file. If the file is large, then it download partially.
Is there a way to control without using a delay?
#!/usr/bin/python3
import pexpect
import time
from subprocess import call
siteip = "131.235.111.111"
ssh_new_conn = 'Are you sure you want to continue connecting'
password = 'xxxxx'
child = pexpect.spawn('ssh admin#' + siteip)
time.sleep(1)
child.expect('admin#.* password:')
child.sendline('xxxxx')
time.sleep(2)
child.expect('admin#.*')
print('ssh to abcd - takes 60 seconds')
child.sendline('backuplog\r')
time.sleep(50)
child.sendline('pwd')
Many pexpect functions take an optional timeout= keyword, and the one you give in spawn() sets the default. Eg
child.expect('admin#',timeout=70)
You can use the value None to never timeout.

Rasa Timeout Issue

When running Rasa (tried on versions 1.3.3, 1.3.7, 1.3.8) I encounter this timeout exception message almost every time I make a call. I am running a simple program that recognises when a user offers their age, and stores the age in a database through an action response:
Bot loaded. Type a message and press enter (use '/stop' to exit):
Your input -> I am 24 years old
2019-10-10 13:29:33 ERROR asyncio - Task exception was never retrieved
future: <Task finished coro=<configure_app.<locals>.run_cmdline_io() done, defined at /Users/Kami/Documents/rasa/venv/lib/python3.7/site-packages/rasa/core/run.py:123> exception=TimeoutError()>
Traceback (most recent call last):
File "/Users/Kami/Documents/rasa/venv/lib/python3.7/site-packages/rasa/core/run.py", line 127, in run_cmdline_io
server_url=constants.DEFAULT_SERVER_FORMAT.format("http", port)
File "/Users/Kami/Documents/rasa/venv/lib/python3.7/site-packages/rasa/core/channels/console.py", line 138, in record_messages
async for response in bot_responses:
File "/Users/Kami/Documents/rasa/venv/lib/python3.7/site-packages/async_generator/_impl.py", line 366, in step
return await ANextIter(self._it, start_fn, *args)
File "/Users/Kami/Documents/rasa/venv/lib/python3.7/site-packages/async_generator/_impl.py", line 205, in throw
return self._invoke(self._it.throw, type, value, traceback)
File "/Users/Kami/Documents/rasa/venv/lib/python3.7/site-packages/async_generator/_impl.py", line 209, in _invoke
result = fn(*args)
File "/Users/Kami/Documents/rasa/venv/lib/python3.7/site-packages/rasa/core/channels/console.py", line 103, in send_message_receive_stream
async for line in resp.content:
File "/Users/Kami/Documents/rasa/venv/lib/python3.7/site-packages/aiohttp/streams.py", line 40, in __anext__
rv = await self.read_func()
File "/Users/Kami/Documents/rasa/venv/lib/python3.7/site-packages/aiohttp/streams.py", line 329, in readline
await self._wait('readline')
File "/Users/Kami/Documents/rasa/venv/lib/python3.7/site-packages/aiohttp/streams.py", line 297, in _wait
await waiter
File "/Users/Kami/Documents/rasa/venv/lib/python3.7/site-packages/aiohttp/helpers.py", line 585, in __exit__
raise asyncio.TimeoutError from None
concurrent.futures._base.TimeoutError
Transport closed # ('127.0.0.1', 63319) and exception experienced during error handling
Originally I thought this timeout was being caused by using large lookup tables for another part of my Rasa program, but for age recognition I am using a simple regex:
## regex:age
- ^(0?[1-9]|[1-9][0-9]|[1][1-9][1-9])$
And even this also causes the timeout.
Please help me solve this. I don't even need to avoid the timeout, I just want to know where I can catch/ignore this exception.
Thanks!
I was fetching data from an API wherein I was getting a Timeout error because it was not able to fetch the data in the default time limit :
Go to the directory: venv/Lib/site-packages/rasa/core/channels/console.py
Change the default value of DEFAULT_STREAM_READING_TIMEOUT_IN_SECONDS to more than 10, in my case I changed it to 30 it worked.
Another reason could be fetching of data again and again within a short period of time which could result in a timeout.
Observations :
When DEFAULT_STREAM_READING_TIMEOUT_IN_SECONDS is set to 10 i get timeout error
When DEFAULT_STREAM_READING_TIMEOUT_IN_SECONDS is set to 30 and keep on running rasa shell again and again I get a timeout error
When DEFAULT_STREAM_READING_TIMEOUT_IN_SECONDS is set to 30 and run rasa shell not frequently it functions perfectly.
Make sure that you uncomment the below code
action_endpoint:
url: "http://localhost:5055/webhook"
in the endpoints.yml. It is used when you are making custom actions to query database.
I had the same problem and it was not solved by increasing timeout.
Make sure you are sending back a 'string' to the rasa shell from rasa action sever. What I mean is, if you are using 'text = ' in your utter_message, make sure that the async result is also a string and not just an object or something else. Change the type if required.
dispatcher.utter_message(text='has to be a string')
Running 'rasa shell -vv' showed me that it is receiving an object and that is why it is not able to parse it, hence timeout.
I can't comment now, but add followup to Vishal response. To check that hooks are present and waiting for connection you can use -vv command line switch. This display all available hooks at startup. For example:
2020-04-21 14:05:56 DEBUG rasa.core.utils - Available web server routes:
/webhooks/rasa GET custom_webhook_RasaChatInput.health
/webhooks/rasa/webhook POST custom_webhook_RasaChatInput.receive
/webhooks/rest GET custom_webhook_RestInput.health
/webhooks/rest/webhook POST custom_webhook_RestInput.receive
/ GET hello

How to I read from a Jupyter iopub socket?

I'm trying to learn more about the Jupyter wire protocol. I want to collect examples of the messages sent on the IOPub socket.
SETUP:
I start a Jupyter console in one terminal then go find the connection file. In my case the contents are as follows:
{
"shell_port": 62690,
"iopub_port": 62691,
"stdin_port": 62692,
"control_port": 62693,
"hb_port": 62694,
"ip": "127.0.0.1",
"key": "9c6bbbfb-6ad699d44a15189c4f3d3371",
"transport": "tcp",
"signature_scheme": "hmac-sha256",
"kernel_name": ""
}
I create a simple python script as follows:
import zmq
iopub_port = "62691"
ip = "127.0.0.1"
transport = "tcp"
context = zmq.Context()
socket = context.socket(zmq.SUB)
socket.connect(f"{transport}://{ip}:{iopub_port}")
while True:
string = socket.recv()
print(string)
I open a second terminal and execute the script as follows (it blocks, as expected):
python3 script.py
And then I switch back to the first terminal (with the Jupyter console running) and start executing code.
ISSUE: Nothing prints on the second terminal.
EXPECTED: Some Jupyter IO messages, or at least some sort of error.
Uh, help? Is my code fine and this is probably an issue with my config? Or is my code somehow braindead?
From one of the owners of the Jupyter client repo:
ZMQ subscriber sockets need a subscription set before they'll receive
any messages. The subscription is a prefix of a valid message, and you
can set it to an empty bytes string to subscribe to all messages.
e.g. in my case I need to add
socket.setsockopt(zmq.SUBSCRIBE, b'')
before starting the while loop.
Do you know if it's possible to capture from IOPub if a process in Jupyter notebook is finished or not?
I'm looking here (http://jupyterlab.github.io/jupyterlab/services/modules/kernelmessage.html) but it is not very clear.

Recieve and reply to sms on huawei modem, gammu-smsd: Process failed with exit status 2

I Have a Huawei E220 HSDPA Modem on linux xubuntu
I wanted to recieve sms and reply automatically to the sender.
I Use gammu and Gammu-smsd to do this.
To automatically send sms back I added runOnRecieve = /path/to/bash/file into the /etc/gammu-smsdrc configuration-file.
Here is the script:
#!/bin/bash
str=$SMS_1_TEXT //string containing text from sender
tlf=$SMS_1_NUMBER //containing number from sender
tlf=${tlf:3}
if test "$str" = "today"; then
echo "[Weather for today in Norway]
Sol, noe overskyet
[Vind fra sørøst]
Ha en fin dag!" | gammu-smsd-inject TEXT $tlf -unicode -autolen 200
else
echo "fail" >> /home/mattis/sms.txt
fi
This is how I start the daemon
$ sudo gammu-smsd
This works if I run the bash script from terminal using test-input, but when the program gammu-smsd calls the script I get.
gammu-smsd[3183]: Process failed with exit status 2
Now i can remove "gammu-smsd-inject" from the code and replace with "gammu sendsms" , but that would just give me gibberish letters instead of "æøå and [ ]" when received back to the mobile.
Hoping for positive answers.
--//--Working code--//--
The thing is: Gammu sms inject acctually sends data to mysql database called smsd.
Creating this database:
This should be created as specified in wammu sql database. Storing the SQL script for creating tables in MySQL database will able you to import it with phpmyadmin(gui) or any other way to interface mysql.
Run on recieve
Add to the end of /etc/gammu-smsdrc --configuration file for gammu
runOnRecieve = /path/to/bash/file
Open the /path/to/bash/file
#!/bin/bash
str=$SMS_1_TEXT //codeword "weather"
tlf=$SMS_1_NUMBER //+47 41412424
tlf=${tlf:3} //remove +47
if test "$tlf" = "41412424"; then
toSend = "[Weather for today in Norway]"
else
toSend = "[you are not part of this group]"
echo "Someone outside the group send to this number" > /home/user/activity.txt
fi
mysql --host=localhost --user=username --password=pw smsd << EOF
INSERT INTO outbox (
DestinationNumber,
TextDecoded,
CreatorID,
RelativeValidity
) VALUES (
'$tlf',
'$toSend',
'Program',
'255'
);
EOF
Start the daemon
$ sudo gammu-smsd
That should be it!
Extra tips:
Use $ gammu-detect to find out where the device is connected. Look for name = Phone on USB serial port HUAWEI_Technology HUAWEI_Mobile or something similar. Put this info in the configfile.
Be shure to add right permission to the bashfile. Make it readable to user running gammu-smsd.
Make the bashfile executable using chmod u+x /path/to/bash/file.
The gammu-smsd-monitor can be used to check how good signal you have. Be shure not to stop running the gammu-smsd when trying to run this.
You can test the bashfile by running it with dummy tlf and dummytext as input. $ ./bashfile.sh.

Resources