Use for loop with dictionary - python-3.x

I'm using Napalm to change the hostname of many network devices. Since the config will be different for each device, I need the script to assign the proper config to each device based on it's IP address. This seems like a dictionary would work best.
devicelist = {'10.255.32.1': 'device1.cfg', '10.255.32.5': 'device2.cfg'}
I need help calling the key value in the script below for each IP address. I have highlighted the line of code where this is required.
from napalm import get_network_driver
devicelist = ['10.255.32.1',
'10.255.32.5'
]
for ip_address in devicelist:
print ("Connecting to " + str(ip_address))
driver = get_network_driver('ios')
iosv = driver(ip_address, 'admin', 'password')
iosv.open()
**iosv.load_merge_candidate(filename='device1.cfg')**
diffs = iosv.compare_config()
if len(diffs) > 0:
print(diffs)
iosv.commit_config()
else:
print('No changes required.')
iosv.discard_config()
iosv.close()

You are asking for a simple access by key on your dictionary, combined with a for loop over the dictionary which is automatically a for loop over the keys. Minimal example:
devicelist = {'10.255.32.1': 'device1.cfg', '10.255.32.5': 'device2.cfg'}
for ipAdress in devicelist:
print("This IP : {} maps to this name: {}".format(ipAdress, devicelist[ipAdress]))
Output:
This IP : 10.255.32.1 maps to this name: device1.cfg
This IP : 10.255.32.5 maps to this name: device2.cfg

Related

Python. Problems populating a dictionary in a loop

I am trying to add geoip information to a bunch of IP addresses I have extracted from netstat. I get my endpoint IPs in my list fine.
DEBUG1: Endpoint IPs: ['165.227.118.82', '155.133.248.39', '20.54.37.64', '173.194.76.188', '74.125.206.109', '47.251.49.246', '52.19.109.21', '151.101.61.229', '151.101.60.193', '162.159.133.234', '162.159.135.232', '162.159.133.232', '162.159.129.232', '75.2.53.94', '54.170.196.176', '143.204.65.104', '34.236.20.64', '75.101.134.98', '75.101.134.98', '75.101.134.98', '52.216.249.68', '52.216.249.68', '142.250.179.228', '142.250.179.228', '52.96.165.18', '52.97.133.194', '52.98.159.194']
But when I try and enrich each of these IPs with additional information via a loop I only get the last IP returned in the dictionary. I ralise it is being over written but I cant see how or why.
Here is what happens when I run the program and I print out the resulting dictionary.
DEBUG2: Enriched IP: {'IP': '52.98.159.194', 'continent': 'Europe', 'country': 'France', 'iso_code': 'FR', 'city': 'Paris', 'lat': 48.8323, 'long': 2.4075, 'timezone': 'Europe/Paris', 'accuracy': 20}
The errant function is as follows:
def enrich_ip(rip):
# ------------------This needs to be a function------------------
# Get ip info on each of the IP's retuned in rip
# add this information to a dictionary
# create a dictionary to hold our ip info
enriched_info = {}
for ip in rip:
# get ip info
try:
enriched_info['IP'] = ip
enriched_info['continent'] = get_ip_info(ip).continent.name
enriched_info['country'] = get_ip_info(ip).country.name
enriched_info['iso_code'] = get_ip_info(ip).country.iso_code
enriched_info['city'] = get_ip_info(ip).city.name
enriched_info['lat'] = get_ip_info(ip).location.latitude
enriched_info['long'] = get_ip_info(ip).location.longitude
enriched_info['timezone'] = get_ip_info(ip).location.time_zone
enriched_info['accuracy'] = get_ip_info(ip).location.accuracy_radius
except Exception as e:
print(e)
continue
return enriched_info
I pass in 'rip' to the function. rip is my list of IPs shown against DEBUG1
I had this working fine outside of a function, but I was then left with the information inside the function and not accessible elsewhere.
Dictionaries cannot contain duplicate keys, that's why you only see the last IP address in resulting dictionary. Instead, create a list of dictionaries and return it:
def enrich_ip(rip):
# ------------------This needs to be a function------------------
# Get ip info on each of the IP's retuned in rip
# add this information to a dictionary
# create a list to hold our ip info
all_data = []
for ip in rip:
enriched_info = {}
try:
enriched_info["IP"] = ip
enriched_info["continent"] = get_ip_info(ip).continent.name
enriched_info["country"] = get_ip_info(ip).country.name
enriched_info["iso_code"] = get_ip_info(ip).country.iso_code
enriched_info["city"] = get_ip_info(ip).city.name
enriched_info["lat"] = get_ip_info(ip).location.latitude
enriched_info["long"] = get_ip_info(ip).location.longitude
enriched_info["timezone"] = get_ip_info(ip).location.time_zone
enriched_info["accuracy"] = get_ip_info(ip).location.accuracy_radius
all_data.append(enriched_info)
except Exception as e:
print(e)
continue
return all_data
Alternative would be to crate a dictionary where keys are IP:
def enrich_ip(rip):
# ------------------This needs to be a function------------------
# Get ip info on each of the IP's retuned in rip
# add this information to a dictionary
# create a dictionary to hold our ip info
all_data = {}
for ip in rip:
enriched_info = {}
try:
enriched_info["IP"] = ip
enriched_info["continent"] = get_ip_info(ip).continent.name
enriched_info["country"] = get_ip_info(ip).country.name
enriched_info["iso_code"] = get_ip_info(ip).country.iso_code
enriched_info["city"] = get_ip_info(ip).city.name
enriched_info["lat"] = get_ip_info(ip).location.latitude
enriched_info["long"] = get_ip_info(ip).location.longitude
enriched_info["timezone"] = get_ip_info(ip).location.time_zone
enriched_info["accuracy"] = get_ip_info(ip).location.accuracy_radius
all_data["IP"] = enriched_info
except Exception as e:
print(e)
continue
return all_data

Scapy & Docker: Get container's IP address w/o using Container ID?

What is the easiest way to compare IP addresses using Scapy (in Python3.6) and Docker? I have a piece of code that sniffs my Docker bridge network using Scapy sniff(). I want to look at each packet's source IP address, and if it matches the IP address for my container named "plc1", do additional steps. If they don't match, I just return an empty list and move on.
However I cannot figure out how to compare a packet's source IP address to a container name. It really needs to be the container's name and not the ID, since I am running a ton of containers in parallel and looking up ID's to plug into my Python3.6 script is tedious. Any thoughts? I've tried using the Docker SDK but it needs the Container ID, which is what I am trying to avoid...
Sample Python3.6 code, which does not work, included below:
#!/usr/bin/env python3
from scapy.all import *
def find_ports(pkt):
# if src IPaddr matches IP addr of container plc1...
if pkt[IP].src == 'plc1': # THIS DOES NOT WORK
# if there is a match, get some additional packet info
if TCP in pkt:
tcp_dport = pkt[TCP].dport
ip_total_len = pkt.getlayer(IP).len
ip_header_len = pkt.getlayer(IP).ihl * 32 / 8
tcp_header_len = pkt.getlayer(TCP).dataofs * 32 / 8
tcp_seg_len = ip_total_len - ip_header_len - tcp_header_len
sequence_num = pkt[1].ack
return [tcp_dport, tcp_seg_len, sequence_num]
# else if NO MATCHING ip addr's, return blank list...
else:
return []
tempList = sniff(filter="ip", prn=find_ports, iface="br-19f0ba1cf88f")
# if templist not empty...
if tempList:
# send a TCP RST packet...
ip = IP(src="plc1", dst="hmi_pass_thru")
tcp = TCP(sport=502, dport=tempList[0], flags="R", seq=int(tempList[1]), ack=int(tempList[2]) + 1)
pkt = ip / tcp
ls(pkt)
send(pkt, verbose=0)

Multiple inputs and lines loop to write to file - python

Currently I'm pasting multiple lines of names which loops through each line and writes into a file. This prompts me to paste values in which works.
However I would like to have another prompt for other values like IPs etc going through the same loop.
Probably something very simple but any help would be appreciated.
Thanks in advance.
subnet = input(('Paste the subnet mask: '))
quit = ''
for line in iter(input, quit):
with open('my_file.yml', 'a') as data_file:
data_file.write(" - host: " + line + "\n ip: " + ips + "\n subnet:
" + subnet)
You can do what you want without iter by using an infinite while that only breaks out when no input is entered. I could have also checked for no input with if not host, because empty strings return False (See: Truth Value Testing).
The file is only opened once. There no need to repeatedly open it each iteration.
I have used an f-string with the call to write(), but you can still use normal strings like you did.
subnet = input('Paste the subnet mask: ')
with open('my_file.yml', 'a') as data_file:
while True:
host = input('Enter host: ')
if host == '':
break
ips = input('Enter IPs: ')
if ips == '':
break
data_file.write(f' - host: {host}\n ip: {ips}\n subnet: {subnet}\n')
Contents of my_file.yml:
- host: localhost
ip: 192.168.0.5
subnet: 255.255.255.0
- host: anotherhost
ip: 192.168.1.1
subnet: 255.255.255.0

How do I get instance id/name from public ip address of VM in azure via python sdk

def get_instance_id_from_pip(self, pip):
subscription_id="69ff3a41-a66a-4d31-8c7d-9a1ef44595c3"
compute_client = ComputeManagementClient(self.credentials, subscription_id)
network_client = NetworkManagementClient(self.credentials, subscription_id)
print("Get all public IP")
for public_ip in network_client.public_ip_addresses.list_all():
if public_ip.ip_address == pip:
print(public_ip)
# Get id
pip_id= public_ip.id.split('/')
print("pip id : {}".format(pip_id))
rg_from_pip = pip_id[4].lower()
print("RG : {}".format(rg_from_pip))
pip_name = pip_id[-1]
print("pip name : {}".format(pip_name))
for vm in compute_client.virtual_machines.list_all():
vm_id = vm.id.split('/')
#print("vm ref id: {}".format(vm_id))
rg_from_vm = vm_id[4].lower()
if rg_from_pip == rg_from_vm:
## this is the VM in the same rg as pip
for ni_reference in vm.network_profile.network_interfaces:
ni_reference = ni_reference.id.split('/')
ni_name = ni_reference[8]
print("ni reference: {}".format(ni_reference))
net_interface = network_client.network_interfaces.get(rg_from_pip, ni_name)
print("net interface ref {}".format(net_interface))
public_ip_reference = net_interface.ip_configurations[0].public_ip_address
if public_ip_reference:
public_ip_reference = public_ip_reference.id.split('/')
ip_group = public_ip_reference[4]
ip_name = public_ip_reference[8]
print("IP group {}, IP name {}".format(ip_group, ip_name))
if ip_name == pip_name:
print("Thank god. Finallly !!!!")
print("VM ID :-> {}".format(vm.id))
return vm.id
I have above code to get the VM instance ID from Public ip but its not working. What is real surprising is that for all instances, I am getting x.public_ip_address.ip_address as None value.
I had multiple readthedocs references for python SDK of Azure. but, some how all links not working. Good job Azure :)
Some of them:
https://azure-sdk-for-python.readthedocs.io/en/v1.0.3/resourcemanagementcomputenetwork.html
https://azure-storage.readthedocs.io/en/latest/ref/azure.storage.file.fileservice.html
Second edit:
I got the answer to this and above code will return vm id given the public ip address. Though, you can see it is not absolutely optimized answer. Hence, better answers are welcome. Thanks!
Docs have moved here:
https://learn.microsoft.com/python/azure/
We made some redirection, but unfortunately it's not possible to go global redirection on RTD, so some pages are 404 :/
About your trouble, I would try to use the publicip operation group directly:
https://learn.microsoft.com/en-us/python/api/azure.mgmt.network.v2017_11_01.operations.publicipaddressesoperations?view=azure-python
You get this one in the Network client, as client.public_ip_addresses

Python - Error querying Solarwinds N-Central via SOAP

I'm using python 3 to write a script that generates a customer report for Solarwinds N-Central. The script uses SOAP to query N-Central and I'm using zeep for this project. While not new to python I am new to SOAP.
When calling the CustomerList fuction I'm getting the TypeError: __init__() got an unexpected keyword argument 'listSOs'
import zeep
wsdl = 'http://' + <server url> + '/dms/services/ServerEI?wsdl'
client = zeep.CachingClient(wsdl=wsdl)
config = {'listSOs': 'true'}
customers = client.service.CustomerList(Username=nc_user, Password=nc_pass, Settings=config)
Per the perameters below 'listSOs' is not only a valid keyword, its the only one accepted.
CustomerList
public com.nable.nobj.ei.Customer[] CustomerList(String username, String password, com.nable.nobj.ei.T_KeyPair[] settings) throws RemoteException
Parameters:
username - MSP N-central username
password - Corresponding MSP N-central password
settings - A list of non default settings stored in a T_KeyPair[]. Below is a list of the acceptable Keys and Values. If not used leave null
(Key) listSOs - (Value) "true" or "false". If true only SOs with be shown, if false only customers and sites will be shown. Default value is false.
I've also tried passing the dictionary as part of a list:
config = []
key = {'listSOs': 'true'}
config += key
TypeError: Any element received object of type 'str', expected lxml.etree._Element or builtins.dict or zeep.objects.T_KeyPair
Omitting the Settings value entirely:
customers = client.service.CustomerList(Username=nc_user, Password=nc_pass)
zeep.exceptions.ValidationError: Missing element Settings (CustomerList.Settings)
And trying zeep's SkipValue:
customers = client.service.CustomerList(Username=nc_user, Password=nc_pass, Settings=zeep.xsd.SkipValue)
zeep.exceptions.Fault: java.lang.NullPointerException
I'm probably missing something simple but I've been banging my head against the wall off and on this for awhile I'm hoping someone can point me in the right direction.
Here's my source code from my getAssets.py script. I did it in Python2.7, easily upgradeable though. Hope it helps someone else, N-central's API documentation is really bad lol.
#pip2.7 install zeep
import zeep, sys, csv, copy
from zeep import helpers
api_username = 'your_ncentral_api_user'
api_password='your_ncentral_api_user_pw'
wsdl = 'https://(yourdomain|tenant)/dms2/services2/ServerEI2?wsdl'
client = zeep.CachingClient(wsdl=wsdl)
response = client.service.deviceList(
username=api_username,
password=api_password,
settings=
{
'key': 'customerId',
'value': 1
}
)
# If you can't tell yet, I code sloppy
devices_list = []
device_dict = {}
dev_inc = 0
max_dict_keys = 0
final_keys = []
for device in response:
# Iterate through all device nodes
for device_properties in device.items:
# Iterate through each device's properties and add it to a dict (keyed array)
device_dict[device_properties.first]=device_properties.second
# Dig further into device properties
device_properties = client.service.devicePropertyList(
username=api_username,
password=api_password,
deviceIDs=device_dict['device.deviceid'],
reverseOrder=False
)
prop_ind = 0 # This is a hacky thing I did to make my CSV writing work
for device_node in device_properties:
for prop_tree in device_node.properties:
for key, value in helpers.serialize_object(prop_tree).items():
prop_ind+=1
device_dict["prop" + str(prop_ind) + "_" + str(key)]=str(value)
# Append the dict to a list (array), giving us a multi dimensional array, you need to do deep copy, as .copy will act like a pointer
devices_list.append(copy.deepcopy(device_dict))
# check to see the amount of keys in the last item
if len(devices_list[-1].keys()) > max_dict_keys:
max_dict_keys = len(devices_list[-1].keys())
final_keys = devices_list[-1].keys()
print "Gathered all the datas of N-central devices count: ",len(devices_list)
# Write the data out to a CSV
with open('output.csv', 'w') as csvfile:
fieldnames = final_keys
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
for csv_line in devices_list:
writer.writerow(csv_line)

Resources