Pysnmp Walk Cisco Prime for Name and AP Connection Count - cisco

I'm using pysnmp to retrieve OID info from Cisco devices. The below code prints out all names of the 1k+ access points associated with the IP.
a = nextCmd(SnmpEngine(), CommunityData('myComm'), UdpTransportTarget((IP_Address, 161)), ContextData(), ObjectType(ObjectIdentity('1.3.6.1.4.1.14179.2.2.1.1.3')))
for errorIndication,errorStatus,errorIndex,varBinds in a:
for v in varBinds:
print(v)
The output looks like this
SNMPv2-SMI::enterprises.xxx.x.x.x.xx.x.160 = cftnnjguapnrs01v100c
SNMPv2-SMI::enterprises.xxx.x.x.x.xx.x.128 = nycmnykyapnrs01v100c
You can see the name payload at the end of the string. Next, I need to get the corresponding connection count for each. However, I don't know how to match the two afterwards. Is there a way to return a tuple for Name, Count, (Location?) in one request?

Related

Is there a way to aggregate values in a column in sqlite in one-to-many relationship into array?

Is there a way to aggregate values in a column in sqlite in one-to-many relationship into array?
For example, I have 2 tables like this:
Artists:
ArtistId name
1 AC/DC
2 Accept
Albums:
AlbumId ArtistId Title
1 1 For Those About To Rock We Salute You
2 1 Let There Be Rock
3 2 Balls to the Wall
4 2 Restless and Wild
When I just do a query with a join:
SELECT
Name,
Title
FROM
artists
JOIN albums USING(ArtistId)
WHERE artists.ArtistId = 1;
I get:
I found out that I can do group_concat:
SELECT
Name,
GROUP_CONCAT(Title)
FROM
artists
JOIN albums USING(ArtistId)
WHERE artists.ArtistId = 1;
To concatenate all values together:
But I still have to parse the coma-separated string with titles: For Those About To Rock We Salute You,Let There Be Rock in the code to get the array of titles for each artist.
I use Python and I'd prefer to get something like a tuple for each row:
(name, titlesArray)
A much easier way in this case for me would be to use json.loads and json.dumps functions to save all the "many" array members into the same row in the same table, instead of using the recommended way for databases to save values in different tables and then use joins to retrieve them: the "many" values is an array on the object, and it's just much easier to save and get them using just 2 functions: json.loads and json.dumps, compared to manually saving the "many" values into a separate table, create binding to the "one" value, then use group_concat to concat them into a string, and then parse it more to actually get my array back.
Is it possible to get an array of values, or do I have to do group_concat and parse the string?
You might not be able to receive an array from sqlite straight away, but you can achieve the result with a very little edit on your query and a single line in python.
group_concat supports a custom delimiter that you can use later to split the entries.
Let's assume you have something like this:
from typing import Typle
import sqlite3
def connect(file: str = None) -> sqlite3.Connection:
connection = None
try:
connection = sqlite3.connect(file)
except sqlite3.Error:
raise
return connection
def select(connection: sqlite3.Connection) -> Tuple(str, str)):
entry = None
try:
sql = """
SELECT
Name,
GROUP_CONCAT(Title)
FROM artists
JOIN albums USING(ArtistId)
WHERE artists.ArtistId = 1;
"""
cursor.execute(sql, parameters)
reply = cursor.fetchone()
if reply is not None:
entry = reply
except sqlite3.Error:
raise
finally:
cursor.close()
return entry
that you can use to connect to the database and select from it like so:
connection = connect(r"/path/to/file.sqlite3")
if connection is not None:
entry = select(connection)
connection.close()
It is not important if your query is inside a function or not, the important concept is that you are using python to do this query, and you can add some code to manipulate the values.
As you can see here group_concat accepts a separator that you can use to arbitrarily separate values.
Your new select function could be something like:
def select(connection: sqlite3.Connection) -> Tuple(str, Tuple(str, ...)):
entry = None
separator = r"|"
try:
sql = f"""
SELECT
Name,
GROUP_CONCAT(Title, {separator})
FROM artists
JOIN albums USING(ArtistId)
WHERE artists.ArtistId = 1;
"""
cursor.execute(sql, parameters)
reply = cursor.fetchone()
if reply is not None:
reply[1] = reply[1].split(separator)
entry = reply
except sqlite3.Error:
raise
finally:
cursor.close()
return entry
Without changing how you use this function, you would now have a tuple with all the titles.
Another idea you'd like to consider is to do a more specific select query, like:
select albums.Title
from albums
where albums.ArtistId = 1;
In this case, you can have a list of titles using: cursor.fetchall().
Of course the band name should be asked separately in this case.

(Beginner Python assignment help) Search input list

I have just started learning python and i have been given an assignment to create a list of players and stats using different loops.
I cant work out how to create a function that searches the player list and gives an output of the players name and the players stat.
Here is the assignment:
Create an empty list called players
Use two input() statements inside a for loop to collect the name
and performance of each player (the name will be in the form of a
string and the performance as an integer from 0 – 100.) Add both
pieces of information to the list (so in the first iteration of the
loop players[0] will contain the name of the first player and
players[1] will contain their performance.) You are not required to
validate this data.
Use a while loop to display all the player information in the
following form:
Player : Performance
Use a loop type of your choice to copy the performance values from
the players list and store these items in a new list called results
Write a function that accepts the values “max” or “min” and
returns the maximum or minimum values from the results list
Write a function called find_player() that accepts a player name
and displays their name and performance from the players list, or an
error message if the player is not found.
Here is what I have so far:
print ("Enter 11 Player names and stats")
# Create player list
playerlist = []
# Create results list
results = []
# for loop setting amount of players and collecting input/appending list
for i in range(11):
player = (input("Player name: "))
playerlist.append(player)
stats = int(input("Player stats: "))
playerlist.append(stats)
# While loop printing player list
whileLoop = True
while whileLoop == True:
print (playerlist)
break
# for loop append results list, [start:stop:step]
for i in range(11):
results.append(playerlist[1::2])
break
# max in a custom function
def getMax(results):
results = (playerlist[1::2])
return max(results)
print ("Max Stat",getMax(results))
# custom function to find player
def find_player(playerlist):
list = playerlist
name = str(input("Search keyword: "))
return (name)
for s in list:
if name in str(s):
return (s)
print (find_player(playerlist))
I have tried many different ways to create the find player function without success.
I think I am having problems because my list consists of strings and integers eg. ['john', 6, 'bill', 8]
I would like it to display the player that was searched for and the stats ['John', 6]
Any help would be greatly appreciated.
PS:
I know there is no need for all these loops but that is what the assignment seems to be asking for.
Thank you
I cut down on the fat and made a "dummy list", but your find_player function seems to work well, once you remove the first return statement! Once you return something, the function just ends.
All it needs is to also display the performance like so:
# Create player list
playerlist = ["a", 1, "b", 2, "c", 3]
# custom function to find player
def find_player(playerlist):
name = str(input("Search keyword: "))
searchIndex = 0
for s in playerlist:
try:
if name == str(s):
return ("Player: '%s' with performance %d" % (name, playerlist[searchIndex+1]))
except Exception as e:
print(e)
searchIndex += 1
print (find_player(playerlist))
>>Search keyword: a
>>Player: 'a' with performance 1
I also added a try/except in case something goes wrong.
Also: NEVER USE "LIST" AS A VARIABLE NAME!
Besides, you already have an internal name for it, so why assign it another name. You can just use playerlist inside the function.
Your code didn't work because you typed a key and immediately returned it. In order for the code to work, you must use the key to find the value. In this task, it is in the format of '' key1 ', value1,' key2 ', value2, ...]. In the function, index is a variable that stores the position of the key. And it finds the position of key through loop. It then returns list [index + 1] to return the value corresponding to the key.
playerlist = []
def find_player(playerlist):
list = playerlist
name = str(input("Search keyword: "))
index = 0
for s in list:
if name == str(s):
return ("This keyword's value: %d" % (list[index+1]))
index+=1
print (find_player(playerlist))

extract just one element from list and write it into a csv as another name

I have a list:
IDs = ["111111111111", "222222222222"]
and create a csv with this code:
for acc in IDs:
with open("/tmp/test.csv", "a+") as f:
test = csv.writer(f)
test.writerow([IDs])
result is:
{'111111111111', '222222222222'}
what i want to do is like:
if IDs == "111111111111":
IDs = "AccountA"
elif IDs == "222222222222":
IDs = "AccountB"
expected result in csv:
Account A
some information about account a i put later on it
Account B
some information about account a i put later on it
How can I achieve the result?
You could use a dictionary. What you do is you create a dictonary with all data. At the left side you would have your input, and and the right side you have your data that your want to write. For this case, take a look at this dictionary:
data = {
'111111111111':'AccountA',
'222222222222':'AccountB'
}
Than, create a loop around your list and create a new list, with the new ids, configured with your data.
new_ids = []
for x in ids:
new_ids.append(data[x])
Now, you can use the new_ids list to use in your write function.
Hope it helps.
Sincerly, Chris Fowl.

Collapsing IP networks with Python ipaddress module

I'm having difficulty using the ipaddress.collapse_addresses() method.
# n is a list of 192.168.0.0/24 networks (1,2,3,4....etc)
def sumnet():
n = nlist()
for net in n:
snet = ipaddress.collapse_addresses(net)
return snet
I'm only getting back the original list:
Collapsed Networks
[IPv4Network('192.168.0.0/24'), IPv4Network('192.168.1.0/24'),
IPv4Network('192.168.2.0/24'), IPv4Network('192.168.3.0/24'),
IPv4Network('192.168.4.0/24'), IPv4Network('192.168.5.0/24'),
IPv4Network('192.168.6.0/24'), IPv4Network('192.168.7.0/24'),
IPv4Network('192.168.8.0/24')]
Assuming your input is a list of IPv4Networks from ipaddress like...
netlist = [ipaddress.IPv4Network('192.168.0.0/24'),
ipaddress.IPv4Network('192.168.1.0/24'),
ipaddress.IPv4Network('192.168.2.0/24'),
ipaddress.IPv4Network('192.168.3.0/24'),
ipaddress.IPv4Network('192.168.4.0/24'),
ipaddress.IPv4Network('192.168.5.0/24'),
ipaddress.IPv4Network('192.168.6.0/24'),
ipaddress.IPv4Network('192.168.7.0/24'),
ipaddress.IPv4Network('192.168.8.0/24')]
and your desired output is
[IPv4Network('192.168.0.0/21'), IPv4Network('192.168.8.0/24')]
All this can be done with...
import ipaddress
def sumnet(netlist):
return list(ipaddress.collapse_addresses(netlist))
netlist = [ipaddress.IPv4Network('192.168.0.0/24'),
ipaddress.IPv4Network('192.168.1.0/24'),
ipaddress.IPv4Network('192.168.2.0/24'),
ipaddress.IPv4Network('192.168.3.0/24'),
ipaddress.IPv4Network('192.168.4.0/24'),
ipaddress.IPv4Network('192.168.5.0/24'),
ipaddress.IPv4Network('192.168.6.0/24'),
ipaddress.IPv4Network('192.168.7.0/24'),
ipaddress.IPv4Network('192.168.8.0/24')]
print(sumnet(netlist))
The collapse_addresses method actually takes an entire list of addresses, you don't have to feed it ip_addresses one by one. It will return a generator for the collapsed network, but you can just convert that to a list to deal with it easier.
Let me know if this is not what you were trying to accomplish.
It is a little hard to understand exactly what your code is supposed to do as the following snippet starts a for loop where it grabs the first ip address collapses it into a generator and returns that generator with that single ip address, without looking at any of the other ip addresses. This however doesn't seem to be consistent with what your question claims the output to be.
for net in n:
snet = ipaddress.collapse_addresses(net)
return snet

Update Sqlite w/ Python: InterfaceError: Error binding parameter 0 and None Type is not subscriptable

I've scraped some websites and stored the html info in a sqlite database. Now, I want to extract and store the email addresses. I'm able to successfully extract and print the id and emails. But, I keep getting TypeError: "'NoneType' object is not subscriptable" and "sqlite3.InterfaceError: Error binding parameter 0 - probably unsupported type" when I try to update the database with these new email addresses.
I've verified that the data types I'm using in the update statement are the same as my database (id is class int and email is str). I've googled a bunch of different examples and mucked around with the syntax alot.
I also tried removing the Where Clause in the update statement but got the same errors.
import sqlite3
import re
conn = sqlite3.connect('spider.sqlite')
cur = conn.cursor()
x = cur.execute('SELECT id, html FROM Pages WHERE html is NOT NULL and email is NULL ORDER BY RANDOM()').fetchone()
#print(x)#for testing purposes
for row in x:
row = cur.fetchone()
id = row[0]
html = row[1]
email = re.findall(b'[a-z0-9\.\-+_]+#[a-z0-9\.\-+_]+\.[a-z]+', html)
#print(email)#testing purposes
if not email:
email = 'no email found'
print(id, email)
cur.execute('''UPDATE pages SET email = ? WHERE id = ? ''', (email, id))
conn.commit
I want the update statement to update the database with the extracted email addresses for the appropriate row.
There are a few things going on here.
First off, you don't want to do this:
for row in x:
row = cur.fetchone()
If you want to iterate over the results returned by the query, you should consider something like this:
for row in cur.fetchall():
id = row[0]
html = row[1]
# ...
To understand the rest of the errors you are seeing, let's take a look at them step by step.
TypeError: "'NoneType' object is not subscriptable":
This is likely generated here:
row = cur.fetchone()
id = row[0]
Cursor.fetchone returns None if the executed query doesn't match any rows or if there are no rows left in the result set. The next line, then, is trying to do None[0] which would raise the error in question.
sqlite3.InterfaceError: Error binding parameter 0 - probably unsupported type:
re.findall returns a list of non-overlapping matches, not an individual match. There's no support for binding a Python list to a sqlite3 text column type. To fix this, you'll need to get the first element from the matched list (if it exists) and then pass that as your email parameter in the UPDATE.
.findall() returns a list.
You want to iterate over that list:
for email in re.findall(..., str(html)):
print(id, email)
cur.execute(...)
Not sure what's going on with that b'[a-z...' expression.
Recommend you use a raw string instead: r'[a-z...'.
It handles regex \ backwhacks nicely.

Resources