Netmiko/Python script not dispaying output from multiple devices - python-3.x

When I run the script it only returns output from the first device.
#!/usr/local/bin/python3.6
import netmiko
from netmiko import ConnectHandler
import getpass
from getpass import getpass
exceptions = (netmiko.ssh_exception.NetMikoTimeoutException, netmiko.ssh_exception.NetMikoAuthenticationException)
router = {
'device_type': 'cisco_ios',
'ip': '10.5.5.1',
'username': 'admin',
'password': getpass(),
'secret': getpass("Enable: "),
'global_delay_factor': 2,
}
switch = {
'device_type': 'cisco_ios',
'ip': '10.5.5.2',
'username': 'admin',
'password': getpass(),
'secret': getpass("Enable: "),
'global_delay_factor': 2,
}
list_of_devices = [router, switch]
for devices in list_of_devices:
connector = ConnectHandler(**devices)
connector.enable()
print(connector)
output = connector.find_prompt()
output += connector.send_command('show ip arp', delay_factor=2)
print(output)
connector.disconnect()

You need to have all of the Netmiko actions inside of the for loop. With your current code, you establish the connection on the first device, then move on to the second device and do something with it. You don't actually do anything with the first device (since the only thing inside the for loop is the ConnectHandler call):
So something like this (for the for-loop section):
list_of_devices = [router, switch]
for devices in list_of_devices:
connector = ConnectHandler(**devices)
connector.enable()
print(connector)
output = connector.find_prompt()
output += connector.send_command('show ip arp', delay_factor=2)
print(output)
connector.disconnect()

Related

How do I write my own challenge_auth method for aiosmtpd?

I'm trying to connect a wildlife camera to my SMTP server but it keeps dropping the connection after being asked for it's username. I've verified that this server works with other wildlife cameras and email clients but always seems to fail with this specific model of wildlife camera. I've tried with no authentication, basic authentication and TLS but none of them work (The camera works with gmail SMTP though).
This is the simple code I'm using.
It seems like I need to modify the challenge_auth method. My question is how do I do that, do I just add another method to the custom handler with handle_DATA in?
import email
from email.header import decode_header
from email import message_from_bytes
from email.policy import default
from aiosmtpd.controller import Controller
from aiosmtpd.smtp import LoginPassword, AuthResult
import os
import sys
import time
import signal
import logging
##setting timezone
os.environ['TZ'] = "Europe/London"
time.tzset()
def onExit( sig, func=None):
print("*************Stopping program*****************")
controller.stop()
exit()
signal.signal(signal.SIGTERM, onExit)
# removes the spaces and replaces with _ so they're valid folder names
def clean(text):
return "".join(c if c.isalnum() else "_" for c in text)
log = logging.getLogger('mail.log')
auth_db = {
b"TestCamera1#gmail.com": b"password1",
b"user2": b"password2",
b"TestCamera1": b"password1",
}
def authenticator_func(server, session, envelope, mechanism, auth_data):
#this deliberately lets everything through
assert isinstance(auth_data, LoginPassword)
username = auth_data.login
password = auth_data.password
return AuthResult(success=True)
def configure_logging():
file_handler = logging.FileHandler("aiosmtpd.log", "a")
stderr_handler = logging.StreamHandler(sys.stderr)
logger = logging.getLogger("mail.log")
fmt = "[%(asctime)s %(levelname)s] %(message)s"
datefmt = None
formatter = logging.Formatter(fmt, datefmt, "%")
stderr_handler.setFormatter(formatter)
logger.addHandler(stderr_handler)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.setLevel(logging.DEBUG)
class CustomHandler:
def handle_exception(self, error):
print("exception occured")
print(error)
return '542 Internal Server Error'
async def handle_DATA(self, server, session, envelope):
peer = session.peer
data = envelope.content # type: bytes
msg = message_from_bytes(envelope.content, policy=default)
# decode the email subject
print("Msg:{}".format(msg))
print("Data:{}".format(data))
print("All of the relevant data has been extracted from the email")
return '250 OK'
if __name__ == '__main__':
configure_logging()
handler = CustomHandler()
#update hostname to your IP
controller = Controller(handler, hostname='0.0.0.0', port=587, authenticator=authenticator_func, auth_required=True,auth_require_tls=False)
# Run the event loop in a separate thread.
controller.start()
while True:
time.sleep(10)
Here's the logs from a reolink go camera that can connect successfully. (I've updated the format 'Username' is being send .e.g from 'User Name:' to 'Username' by editing the library but that hasn't seemed to help with the suntek camera. I thought it might be more pick with the format due to cheaper, less robust firmware.

python script for cisco traceroute - dont see the entire hops

trying to run python traceroute script
trace stuck after 5-7 hops (not 30 as should be).
attached my script
#!/usr/bin/env python
from netmiko import ConnectHandler
from auto_encrypter_new import *
ios = {
'device_type': 'cisco_ios',
'ip': 'my_ip_device',
'username': user_encrypt,
'password': passwd_encrypt,
}
net_connect = ConnectHandler(**ios)
output = net_connect.send_command_timing('trace dest_ip')
print (output)
get only 6 hops
while doing this via our router i get more hops
any suggestion why ?
Thanks
this might be due to the timeout issue. Try:
output = net_connect.send_command_timing(f'trace {dest_ip}', delay_factor=4)
delay factor is explained here
if it still doesn't work try:
import time
from netmiko import ConnectHandler
from auto_encrypter_new import *
ios = {
'device_type': 'cisco_ios',
'ip': 'my_ip_device',
'username': user_encrypt,
'password': passwd_encrypt,
}
net_connect = ConnectHandler(**ios)
dest_ip = '8.8.8.8'
net_connect.write_channel(f'trace {dest_ip}')
time.sleep(10) # this is needed for the device to send a response. Test it and try to adjust timing if needed
output = net_connect.read_channel()
print(output)

How to store websockets at the server side with aiohttp?

I'm trying to make simple web-chat with rooms using aiohttp. Can you please advise me how to store my websockets connections? Some code below are simplified a bit. I'm getting an EOF error from socket time by time (and I can reproduce it), but i don't know why. So, i got a question, am i do it right? Should i close websockets everytime when i reload or follow to link? If not, so, how i will connect client with my already opened socket? Sorry for my eng ^^ thanks.
app.py
import asyncio
import aiohttp_jinja2
import jinja2
import hashlib
import collections
import os
from aiohttp_session import session_middleware
from aiohttp_session.cookie_storage import EncryptedCookieStorage
from aiohttp import web
from routes import routes
from middlewares import authorize
from motor import motor_asyncio as ma
from settings import *
basedir = os.path.dirname(os.path.realpath(__file__))
photo_dir = os.path.join(basedir, 'static/photo/')
async def on_shutdown(app):
for ws in app['websockets']:
await ws.close(code=1001, mesage='Server shutdown')
middle = [
session_middleware(EncryptedCookieStorage(hashlib.sha256(bytes(SECRET_KEY, 'utf-8')).digest())),
authorize
]
app = web.Application(middlewares=middle)
aiohttp_jinja2.setup(app, loader=jinja2.FileSystemLoader('templates'))
for route in routes:
app.router.add_route(*route[:3], name=route[3])
app['static_root_url'] = '/static'
app.router.add_static('/static', 'static', name='static')
app.client = ma.AsyncIOMotorClient(MONGO_HOST)
app.db = app.client[MONGO_DB_NAME]
app.on_cleanup.append(on_shutdown)
app['websockets'] = collections.defaultdict(list)
app['online'] = {}
app['photo_dir'] = photo_dir
web.run_app(app)
and websocket handler
class CompanyWebSocket(web.View):
async def get(self):
ws = web.WebSocketResponse()
await ws.prepare(self.request)
session = await get_session(self.request)
self_id = session.get('user')
login = session.get('login')
company_id = self.request.rel_url.query.get('company_id')
message = Message(self.request.app.db)
company = Company(self.request.app.db)
my_companys = await company.get_company_by_user(self_id)
for c in my_companys:
self.request.app['websockets'][str(c['_id'])].append(ws)
async for msg in ws:
if msg.type == WSMsgType.TEXT:
if msg.data == 'close':
await ws.close()
else:
await message.save_for_company({'data': 'data'})
mess = {
'data': 'data'
}
# send mess to users in company
for company_ws in self.request.app['websockets'][company_id]:
await company_ws.send_json(mess)
elif msg.type == WSMsgType.ERROR:
log.debug('ws connection closed with exception %s' % ws.exception())
try:
self.request.app['websockets'][company_id].remove(ws)
except:
pass
for _ws in self.request.app['websockets'][company_id]:
await _ws.send_json({'user': login, 'type': 'left'})
return ws

How do I receive new responses in the Websocket?

I have a client module:
#!/usr/bin/env python
# WS client example
import asyncio
import websockets
async def hello():
async with websockets.connect(
'ws://A.B.C.D:8765') as websocket:
name = input("What's your name? ")
await websocket.send(name)
greeting = await websocket.recv()
print(greeting)
asyncio.get_event_loop().run_until_complete(hello())
and the server module:
from __future__ import print_function
#!/usr/bin/env python
import asyncio
import datetime
import random
import websockets
import ast
from collections import defaultdict
import csv
import datetime
from itertools import chain
import json
import os
import operator
import sys
import pymongo
from pymongo import MongoClient
try:
client = MongoClient('localhost', 27017)
db = client["Bubble"]
except Exception as e:
print(e)
start_match = datetime.datetime.strptime(
"2018-07-01 18:00:00", '%Y-%m-%d %H:%M:%S')
collection = "CRODEN_R16"
async def hello(websocket, path):
entity_name = await websocket.recv()
print(entity_name)
while True:
file = open("set_start_match.txt", "r")
for line in file:
start_today = datetime.datetime.strptime(
line.split('.')[0], '%Y-%m-%d %H:%M:%S')
print(start_today)
now = datetime.datetime.utcnow()
diff = now - start_today
request_match = start_match + diff
print(diff)
for post in db[collection].find():
if "emotion" not in post.keys():
print("Ignored")
continue
if post["timeStamp"] > request_match:
if post["entity_name"] == entity_name:
print("Satisfied")
currDict = {}
currDict["entity"] = post["entity_name"]
currDict["emotion"] = max(
post["emotion"].items(), key=operator.itemgetter(1))[0]
currDict["profile_image"] = post["userProfile"]
currDict["tweet"] = post["tweet"]
currDict_json = json.dumps(currDict, default=str)
print(currDict["tweet"])
await websocket.send(currDict_json)
await asyncio.sleep(1)
del currDict
try:
start_server = websockets.serve(hello, '0.0.0.0', 8765)
print("Start entity server")
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
except Exception as e:
print(e)
Now, the issue is that I want to send name as an input only once and receive the output continuously.
When I wrote this in client:
while True:
greeting = await.websocket.recv()
print(greeting)
The same response is returned again and again. Even on the server side, where I am printing the rendered results from db, I am printing the same doc.
I am completely clueless as to what is the issue?
Note: I have tried to the run the once-run client module and there I was getting perfect results. It was just that I had to give the same input again and again. I want it to be automated.
To get data continuously someone has to send data continuously.
If someone sends data continuously then someone else has to get data continuously.
So both sides need loop.
client - it sends numbers continuously in loop.
#!/usr/bin/env python
import asyncio
import websockets
import time
async def hello():
async with websockets.connect(
'ws://localhost:8769') as websocket:
name = input("What's your name? ")
await websocket.send(name)
i = 0
while True:
print('send:', i)
await websocket.send(str(i))
time.sleep(2)
i += 1
try:
asyncio.get_event_loop().run_until_complete(hello())
except KeyboardInterrupt:
print('KeyboardInterrupt')
server - it receives numbers continuously in loop
import asyncio
import websockets
async def hello(websocket, path):
entity_name = await websocket.recv()
print('name:', entity_name)
while True:
data = await websocket.recv()
print('recv:', data)
try:
print("Start entity server")
start_server = websockets.serve(hello, '0.0.0.0', 8769)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
except KeyboardInterrupt: # keyboard need special except
print("KeyboardInterrupt")
start_server.ws_server.close() # solutin for [Errno 98]
except Exception as ex:
print(ex)

Tornado get input from URL request

My program is to get parameter(URL) from web and in my tornado API, i want to accept them into one bye one. Now my code accepts a single tuple. My api want to fetch the 4 parameters(south-lat,south-long,east-lat,east-long) which comes from the web URL request. And i will implement them into get method of Tornado and find them in my database. I want to know how to accept them in tornado in seperately. This is my current working codes.
import socket
import tornado.web
from datetime import datetime
import pymongo
from pymongo import MongoClient
from pprint import pprint
import tornado.httpserver
import tornado.ioloop
import tornado.options
from tornado.options import define,options
#apicall/v1/geoloc.json?geoquery=True&southwest_lat=''&southwest_lng=''&northeast_lat=''&northeast_lng=''
#tornado port
port = 8088
host = "127.0.0.1"
#make a connection with mongodb
#client=MongoClient()
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("hello APIs")
#what this works is here
class VisualizationHandler(tornado.web.RequestHandler):
def get(self,*args):#how to accept the input from map?
self.open_args=args
#self.open_kwargs=kwargs
print(self.open_args)
print(type(self.open_args))
#self.write("Data is at the terminal")
#client = MongoClient("mongodb://localhost:27017")
#db=client.test
#docs=db.neighborhoods.findOne()
#if docs is None:
#print("Not found")
#else:
#print(docs)
#lat=self.get_argument('lat',True)
#long=self.get_argument('long',True)
#self.write(lat)
#self.write(long)
#var neighborhood = db.neighborhoods.findOne( { geometry: { $geoIntersects: { $geometry: { type: "Point", coordinates: [ slong, slat] } } } } )
def main():
application = tornado.web.Application([
(r"/", MainHandler),
(r"/geo/(.*)",VisualizationHandler),
])
try:
sockets = tornado.netutil.bind_sockets(port, address=host)
print("Socket binding successful to {0}:{1}".format(host, port))
except socket.error:
print("Socket binding failed to {0}:{1}".format(host, port))
return
try:
_id = tornado.process.fork_processes(0, max_restarts=3)
print("Process forked : {}".format(_id))
server = tornado.httpserver.HTTPServer(application)
server.add_sockets(sockets)
tornado.ioloop.IOLoop.current().start()
except KeyboardInterrupt: # stop with Ctrl+C from shell
print("Tornado is stopping")
if __name__ == "__main__":
print("Tornado is starting")
main()
get() method's args/kwargs are retrieved from the url (url regex's match groups, to be specific). Of course, you can create something like this to pass arguments to your function:
(r"/geo/(.*)/(.*)", VisualizationHandler)
or
(r"/geo/(?P<south_lat>.*)/(?P<south_long>.*)", VisualizationHandler)
and args/kwargs south_lat and south_long would be passed to your function from a URL like /geo/123/456, but it's inconvenient. I'd advise you to pass your arguments as URL params /geo?south_lat=123&south_long=456 and read them using get_argument().

Resources