SSH and Ping to hosts concurrently with Python asyncio? - ssh

I'm trying to SSH/Ping to hosts concurrently, but I don't see any result so for, probably my implementation isn't correct. This is what I have so far. Any idea appreciated.
import paramiko
import time
import asyncio
import subprocess
async def sshTest(ipaddress,deviceUsername,devicePassword,sshPort): #finalDict
try:
print("Performing SSH Connection to the device")
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(ipaddress, username=deviceUsername, password=devicePassword, port=sshPort, look_for_keys=False, allow_agent=False)
print("Channel established")
except Exception as e:
print(e)
async def pingf(ip):
p1 = subprocess.Popen(['ping', '-c','5', ip], stdout=subprocess.PIPE)
output = p1.communicate()[0]
print(output)
async def main():
taskA = loop.create_task(sshTest('192.168.255.68','admin','admin','22'))
taskB = loop.create_task(sshTest('192.168.254.108','admin','admin','22'))
taskC = loop.create_task(sshTest('192.168.249.134','admin','admin','22'))
taskD = loop.create_task(sshTest('192.168.254.108','admin','admin','22'))
task1 = loop.create_task(pingf('192.168.255.68'))
task2 = loop.create_task(pingf('192.168.254.108'))
task3 = loop.create_task(pingf('192.168.249.134'))
task4 = loop.create_task(pingf('192.168.254.108'))
await asyncio.wait([taskA,taskB,taskC,taskD,task1,task2,task3,task4])
if __name__ == "__main__":
start = time.time()
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
end = time.time()
print("The time of execution of above program is :", end-start)

Asyncio is a form of cooperative multitasking. This means that in order for tasks to run concurrently, a task must explicitly yield control back to the scheduler, which in Python means "your tasks need to await on something".
Neither of your tasks ever calls await, so they're not going to run concurrently. What you have right now is going to run serially.
If you want to run ssh connections concurrently, you're going to have to either:
Replace paramiko with something like AsyncSSH, which is written to work with asyncio, or
Use threading or multiprocessing to parallelize your tasks, rather than using asyncio.
Additionally, if you're working with asyncio, anything that involves running an external command (such as your pingf task) is going to need to use asyncio's run_in_executor method.
For the example you've shown here, I would suggest instead using the concurrent.futures module. Your code might end up looking something like this (I've modified the code to run in my test environment and given the sshTest task something to do beyond simply connecting):
import concurrent.futures
import paramiko
import asyncio
import subprocess
def sshTest(ipaddress, deviceUsername, devicePassword, sshPort): # finalDict
try:
print("Performing SSH Connection to the device")
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(
ipaddress,
username=deviceUsername,
password=devicePassword,
port=sshPort,
look_for_keys=True,
allow_agent=True,
)
stdin, stdout, stderr = client.exec_command("sh -c 'sleep 2; uptime'")
output = stdout.read()
return output
except Exception:
return "failed to connect"
def pingf(ip):
output = subprocess.check_output(["ping", "-c", "5", ip])
return output
def main():
futures = []
with concurrent.futures.ThreadPoolExecutor() as pool:
futures.append(pool.submit(sshTest, "localhost", "root", "admin", "2200"))
futures.append(pool.submit(sshTest, "localhost", "root", "admin", "2201"))
futures.append(pool.submit(sshTest, "localhost", "root", "admin", "2202"))
futures.append(pool.submit(pingf, "192.168.1.1"))
futures.append(pool.submit(pingf, "192.168.1.5"))
futures.append(pool.submit(pingf, "192.168.1.254"))
for future in concurrent.futures.as_completed(futures):
print("return value from task:", future.result())
if __name__ == "__main__":
main()

Related

Having trouble running multiple functions in Asyncio

I'm a novice programmer looking to build a script that reads a list of leads from Google Sheets and then messages them on telegram. I want to separate out the first and second message by three days thats why im separating the methods.
import asyncio
from telethon import TelegramClient
from telethon.errors.rpcerrorlist import SessionPasswordNeededError
import logging
from async_class import AsyncClass, AsyncObject, task, link
from sheetdata import *
logging.basicConfig(format='[%(levelname) 5s/%(asctime)s] %(name)s: %(message)s',
level=logging.WARNING)
api_id = id
api_hash = 'hash'
phone='phone'
username='user'
client = TelegramClient(username, api_id, api_hash)
#already been touched once
second_touch_array=[]
#touched twice
third_touch_array=[]
async def messageCount(userid):
count = 0
async for message in client.iter_messages(userid):
count+=1
yield count
async def firstMessage():
#clear prospects from array and readData from google sheet
clearProspects()
readData(sheet)
#loop through prospects and send first message
for user in prospect_array:
#check if we already messaged the prospect. If we haven't, execute function
if(messageCount(user.id) == 0):
await client.send_message(user.id, 'Hi')
second_touch_array.append(prospect(user.name, user.company, user.id))
print("First Message Sent!")
else:
print("Already messaged!")
async def secondMessage():
for user in second_touch_array:
if(messageCount(user.id) == 1):
await client.send_message(user.id, 'Hello')
third_touch_array.append(prospect(user.name, user.company, user.id))
print("Second Message Sent!")
else:
print("Prospect has already replied!")
async def main():
# Getting information about yourself
me = await client.get_me()
await firstMessage()
await secondMessage()
for user in second_touch_array:
print(user.name, user.company, user.id)
with client:
client.loop.run_until_complete(main())
Anyways, when I run my code i'm successfully getting the "Already Messaged!" print statement in my terminal from the firstMessage function.
This is good - it's detecting I've already messaged the one user on my Google Sheets list; however, my second function isn't being called at all. I'm not getting any print statement and every time I try to print the contents of the second array nothing happens.
If you have any advice it would be greatly appreciated :)

How can I remove messages from an ActiveMQ queue using Python?

I have an ActiveMQ queue which has several messages that were sent using persistent set to true. When I create a subscriber in Python to read the queue, I get all of the messages in the queue. The next time I open the subscriber, I get all of the same messages. I adjusted the code that writes to the queue to set persistent to false, but the message remains in the queue. Have I neglected to send an acknowledgement?
The code is written using Python 2.7 because that's what our customer is using. I'd love to upgrade them, but I don't have the time.
Here's the script that reads the queue:
import socket
import threading
import xml.etree.ElementTree as etree
from xml.dom import minidom # for pretty printing
# import SampleXML
import sys
import os
import math
import time
from time import monotonic
import string
import stomp # for queue support
import platform
class ConnectionListener(stomp.ConnectionListener):
def __init__(self, connection):
self.connection = connection
print ("Listener created")
def on_message(self, message):
print ("Received message with body ") + message.body
class Reader:
def __init__(self):
pass
def ConnectToQueue(self):
#For Production
user = os.getenv("ACTIVEMQ_USER") or "worthington"
#user = os.getenv("ACTIVEMQ_USER") or "worthington_test"
password = os.getenv("ACTIVEMQ_PASSWORD") or "level3"
host = os.getenv("ACTIVEMQ_HOST") or "localhost"
port = os.getenv("ACTIVEMQ_PORT") or 61613
# destination = sys.argv[1:2] or ["/topic/event"]
# destination = destination[0]
dest = "from_entec_test"
#For Production
# dest = "from_entec"
try:
conn = stomp.Connection10(host_and_ports = [(host, port)])
conn.set_listener('message', ConnectionListener(conn))
# conn.start()
# subscribe_id = '-'.join(map(str, (platform.node(), os.getppid(), os.getpid())))
conn.connect(login=user,passcode=password)
subscribe_id = "Queue Test Listener"
conn.subscribe(destination=dest, id=subscribe_id, ack='client-individual')
conn.unsubscribe(id=subscribe_id)
conn.disconnect()
except Exception as error:
reason = str(error)
print("Exception when readig data from queue: " + str(error))
pass
if __name__ == "__main__" :
try:
UploadData = Reader()
UploadData.ConnectToQueue()
print ("Reader finished.")
except Exception as Value:
reason = str(Value)
pass
And here's the code that writes to it:
import socket
import threading
import xml.etree.ElementTree as etree
from xml.dom import minidom # for pretty printing
# import SampleXML
import sys
import os
import math
import time
from time import monotonic
import string
import stomp # for queue support
import platform
class ConnectionListener(stomp.ConnectionListener):
def __init__(self, connection):
self.connection = connection
print "Listener created"
def on_message(self, message):
print "Received message with body " + message.body
class UploadData:
def __init__(self):
pass
def ConnectToQueue(self):
#For Production
user = os.getenv("ACTIVEMQ_USER") or "worthington"
#user = os.getenv("ACTIVEMQ_USER") or "worthington_test"
password = os.getenv("ACTIVEMQ_PASSWORD") or "level3"
host = os.getenv("ACTIVEMQ_HOST") or "localhost"
port = os.getenv("ACTIVEMQ_PORT") or 61613
# destination = sys.argv[1:2] or ["/topic/event"]
# destination = destination[0]
dest = "from_entec_test"
#For Production
# dest = "from_entec"
try:
conn = stomp.Connection10(host_and_ports = [(host, port)])
# conn.start()
# subscribe_id = '-'.join(map(str, (platform.node(), os.getppid(), os.getpid())))
subscribe_id = "Queue Test Listener"
conn.connect(login=user,passcode=password)
message = "This is a test message."
conn.send(dest, message, persistent='true')
print "Sent message containing: " + message
conn.disconnect()
except Exception, error:
reason = str(error)
print "Exception when writing data to queue: " + str(error)
pass
if __name__ == "__main__" :
try:
UploadData = UploadData()
UploadData.ConnectToQueue()
except Exception, Value:
reason = str(Value)
print "Main routine exception: " + str(Value)
pass
I'm not very familiar with Python STOMP clients but from the code you appear to be subscribing using the 'client-individual' mode of STOMP which means that each message you receive requires you to send an ACK frame back with the message Id value so that the remote can mark it as consumed. Since you are not doing that the messages will not be removed from the Queue.
As an alternative you can use the 'auto' acknowledgement mode which marks the message as consumed as soon as the broker dispatches them. To understand the STOMP subscription model please refer to the STOMP specification.

See all of the unique IDs related to a vmware virtual machine

I want to see all of the unique IDs that are specific for a virtual machine such as:
hardware ID, CPU ID, UUID , Mac address and etc.
could anybody please help me to find these IDs??
I can help you finding some of these. For rest of the things you have to search the doc.
Install pyVmomi and run the following code.
EDIT: Changed the code to run on esx host. Simply run it by python .py
Now to know how this code is working. You have to learn Manged Objects. For example here we are working with the Manged Object vm and this object has many properties listed in the doc. So to retrieve uuid of a vm we are invoking vm.config.uuid. Regarding other details you have to go through the VirtualMachine object see what all properties you nedd.
import sys
import atexit
import time
from pyVmomi import vim, vmodl
from pyVim.connect import Disconnect
from pyVim import connect
inputs = {'esx_ip': '15.22.10.10',
'esx_password': 'Password123',
'esx_user': 'root',
'vm_name': 'ubuntu',
}
def wait_for_task(task, actionName='job', hideResult=False):
"""
Waits and provides updates on a vSphere task
"""
while task.info.state == vim.TaskInfo.State.running:
time.sleep(2)
if task.info.state == vim.TaskInfo.State.success:
if task.info.result is not None and not hideResult:
out = '%s completed successfully, result: %s' % (actionName, task.info.result)
print out
else:
out = '%s completed successfully.' % actionName
print out
else:
out = '%s did not complete successfully: %s' % (actionName, task.info.error)
raise task.info.error
print out
return task.info.result
def get_obj(content, vimtype, name):
"""
Get the vsphere object associated with a given text name
"""
obj = None
container = content.viewManager.CreateContainerView(content.rootFolder, vimtype, True)
for c in container.view:
if c.name == name:
obj = c
break
return obj
def main():
si = None
try:
print "Trying to connect ..."
si = connect.Connect(inputs['vcenter_ip'], 443, inputs['vcenter_user'], inputs['vcenter_password'])
except IOError, e:
pass
if not si:
print "Cannot connect to specified host using specified username and password"
sys.exit()
print "Connected to vcenter!"
atexit.register(Disconnect, si)
content = si.RetrieveContent()
# Get the VirtualMachine Object
vm = get_obj(content, [vim.VirtualMachine], inputs['vm_name'])
print "GuestID: ", vm.config.guestId
print "UUID: ", vm.config.uuid
print "Version: ", vm.config.version
for device in vm.config.hardware.device:
if isinstance(device, vim.vm.device.VirtualEthernetCard):
print "MAC Address: ", device.macAddress
#Example of changing UUID:
new_uuid = '423ffff0-5d62-d040-248c-4538ae2c734f'
vmconf = vim.vm.ConfigSpec()
vmconf.uuid = new_uuid
task = vm.ReconfigVM_Task(vmconf)
wait_for_task(task, si)
print "Successfully changed UUID"
print "New UUID: ", vm.config.uuid
if __name__ == "__main__":
main()

tornado's AsyncHttpTestCase is not available outside self.fetch

I have an AsyncHttpTestCase and I want to access it from methods besides self.fetch. Specifically, I have a SockJS handler that I want a sockjs-client to attach too for my tests.
I've discovered that even though self.get_url('/foo') returns a valid url, that url does not respond to anything except for self.fetch(). What gives?
Is this just not possible with AsyncHttpTestCase? What is the best pattern for doing this?
Here's tests.py
import urllib2
from tornado.httpclient import AsyncHTTPClient
import tornado.testing
from tornado.testing import AsyncTestCase, AsyncHTTPTestCase
from app import DebugApp
class TestDebug(AsyncHTTPTestCase):
def get_app(self):
return DebugApp()
def test_foo(self):
response = self.fetch('/foo')
print response.body
assert response.body == 'derp'
def test_foo_from_urllib(self):
response = urllib2.urlopen(self.get_url('/foo'), None, 2)
print response
assert response.body == 'derp'
def runTest(self):
pass
and app.py
import tornado.httpserver
import tornado.ioloop
import tornado.web
from tornado.options import options
class FooHandler(tornado.web.RequestHandler):
def get(self):
self.write("derp")
url_patterns = [
(r"/foo", FooHandler),
]
class DebugApp(tornado.web.Application):
def __init__(self):
tornado.web.Application.__init__(self, url_patterns, debug=True, xsrf_cookies=False)
def main():
app = DebugApp()
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(6006)
tornado.ioloop.IOLoop.instance().start()
if __name__ == "__main__":
main()
and runtest.py
#!/usr/bin/env python
import unittest
from os import path
import sys
import tornado.testing
PROJECT_PATH = path.dirname(path.abspath(__file__))
sys.path.append(PROJECT_PATH)
def all():
suite = unittest.defaultTestLoader.discover('./', 'tests.py', path.dirname(path.abspath(__file__)))
print suite
return suite
if __name__ == '__main__':
# Print a nice message so that we can differentiate between test runs
print ''
print '%s %s' % ('Debug app', '0.1.0')
print '\033[92m' + '-------------- Running Test Suite --------------' + '\033[0m'
print ''
tornado.testing.main()
The problem is that the IOLoop is not running when you call urlopen (and it cannot be, because urlopen is a blocking function). You must run the IOLoop (with either #gen_test, self.wait(), or indirectly via methods like self.fetch()) for the server to respond, and you can only interact with it via non-blocking functions (or if you must use blocking functions like urlopen, run them in a separate thread).

How do I catch SocketExceptions in MonkeyRunner?

When using MonkeyRunner, every so often I get an error like:
120830 18:39:32.755:S [MainThread] [com.android.chimpchat.adb.AdbChimpDevice] Unable to get variable: display.density
120830 18:39:32.755:S [MainThread] [com.android.chimpchat.adb.AdbChimpDevice]java.net.SocketException: Connection reset
From what I've read, sometimes the adb connection goes bad, and you need to reconnect. The only problem is, I'm not able to catch the SocketException. I'll wrap my code like so:
try:
density = self.device.getProperty('display.density')
except:
print 'This will never print.'
But the exception is apparently not raised all the way to the caller. I've verified that MonkeyRunner/jython can catch Java exceptions the way I'd expect:
>>> from java.io import FileInputStream
>>> def test_java_exceptions():
... try:
... FileInputStream('bad mojo')
... except:
... print 'Caught it!'
...
>>> test_java_exceptions()
Caught it!
How can I deal with these socket exceptions?
You will get that error every odd time you start MonkeyRunner because the monkey --port 12345 command on the device isn't stopped when your script stops. It is a bug in monkey.
A nicer way to solve this issue is killing monkey when SIGINT is sent to your script (when you ctrl+c). In other words: $ killall com.android.commands.monkey.
Quick way to do it:
from sys, signal
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
device = None
def execute():
device = MonkeyRunner.waitForConnection()
# your code
def exitGracefully(self, signum, frame=None):
signal.signal(signal.SIGINT, signal.getsignal(signal.SIGINT))
device.shell('killall com.android.commands.monkey')
sys.exit(1)
if __name__ == '__main__':
signal.signal(signal.SIGINT, exitGracefully)
execute()
Edit:
as an addendum, I also found a way to notice the Java errors: Monkey Runner throwing socket exception broken pipe on touuch
Edit:
The signal seems to require 2 parameters, not sure it's always the case, made the third optional.
Below is the workaround I ended up using. Any function that can suffer from adb failures just needs to use the following decorator:
from subprocess import call, PIPE, Popen
from time import sleep
def check_connection(f):
"""
adb is unstable and cannot be trusted. When there's a problem, a
SocketException will be thrown, but caught internally by MonkeyRunner
and simply logged. As a hacky solution, this checks if the stderr log
grows after f is called (a false positive isn't going to cause any harm).
If so, the connection will be repaired and the decorated function/method
will be called again.
Make sure that stderr is redirected at the command line to the file
specified by config.STDERR. Also, this decorator will only work for
functions/methods that take a Device object as the first argument.
"""
def wrapper(*args, **kwargs):
while True:
cmd = "wc -l %s | awk '{print $1}'" % config.STDERR
p = Popen(cmd, shell=True, stdout=PIPE)
(line_count_pre, stderr) = p.communicate()
line_count_pre = line_count_pre.strip()
f(*args, **kwargs)
p = Popen(cmd, shell=True, stdout=PIPE)
(line_count_post, stderr) = p.communicate()
line_count_post = line_count_post.strip()
if line_count_pre == line_count_post:
# the connection was fine
break
print 'Connection error. Restarting adb...'
sleep(1)
call('adb kill-server', shell=True)
call('adb start-server', shell=True)
args[0].connection = MonkeyRunner.waitForConnection()
return wrapper
Because this may create a new connection, you need to wrap your current connection in a Device object so that it can be changed. Here's my Device class (most of the class is for convenience, the only thing that's necessary is the connection member:
class Device:
def __init__(self):
self.connection = MonkeyRunner.waitForConnection()
self.width = int(self.connection.getProperty('display.width'))
self.height = int(self.connection.getProperty('display.height'))
self.model = self.connection.getProperty('build.model')
def touch(self, x, y, press=MonkeyDevice.DOWN_AND_UP):
self.connection.touch(x, y, press)
An example on how to use the decorator:
#check_connection
def screenshot(device, filename):
screen = device.connection.takeSnapshot()
screen.writeToFile(filename + '.png', 'png')