-
Notifications
You must be signed in to change notification settings - Fork 0
DO NOT MERGE #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
DO NOT MERGE #1
Conversation
# Where i'm pulling the devices list / Soon I'll make this automated which will pull direct from NARF | ||
file = open(r'/home/segattod/segattod-workspace/src/Segattod-package/myproject/Light_level_checks/list.txt', | ||
'r') | ||
file = file.read().splitlines() | ||
|
||
username = input('User Name:') | ||
password = getpass.getpass() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a general rule, these should be inside a method. There isn't really any reason to have commands outside of a method. Save the top up here for declaring constants, and everything else gets wrapped up tidy.
# for now just to name the file / Soon to add for user to add input :) | ||
whid = 'YEG1' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By convention, names of constants are always in all caps
# for now just to name the file / Soon to add for user to add input :) | |
whid = 'YEG1' | |
WHID = 'YEG1' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay, even if later I'll make it to ask user the "whid "input, I should make it all capital to mean it should not changed, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm actually talking about that in the other file I'm going to upload. it's an interesting one. In general, the value should never change so I'd say yes, all caps. BUT from the other point of view, it IS changing once because it is being set. In the end, it could go either way, I guess.
# Variable for "append" the data later | ||
formatted_data = [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would get moved into "main" when you implement it.
|
||
|
||
# Function to sorte the data | ||
def light_level_check(connection): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By convention, starting a method/function name with an underscore shows others that it's not meant for them to use. If someone builds on your package, would you expect them to want to use this function? If so, then this should return as you mentioned below. if not, then start it with an underscore and it can do whatever it wants because it's "private".
In this case, it's up to you. but defaulting to an underscore is never a bad idea.
def light_level_check(connection): | ||
# Command to checks light level per interface | ||
transceiver_output = connection.send_command('show interface transceiver', read_timeout=90, | ||
use_textfsm='~/ntc-templates/ntc_templates/templates/cisco_ios_show_interface_transceiver.textfsm') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the code for send_command
, use_textfsm
is a boolean so it expects True or False. I suspect you meant to use textfsm_template
there?
You didn't get any errors here because Python is a "Truthy" language. When it expects a boolean and it gets pretty much anything, it assumes that is True. It's smart enough to know that an empty string is False, and the integer 0 is false, but the string "banana" or any number other than 0 is treated as a True.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure if i get your question right, but zthe output from this command will be formatted as the textfsm template, which should look just like json.
here is the output how it looks like (ps: i added just 2 lines/interfaces output but it could have many)
output = [
{
"iface": "Te1/0/39",
"temperature": "36.1",
"voltage": "3.29",
"tx_pwr": "41.8",
"rx_pwr": "-2.5"
},
{
"iface": "Te1/0/40",
"temperature": "35.1",
"voltage": "3.30",
"tx_pwr": "36.5",
"rx_pwr": "-2.1"
}
]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://ktbyers.github.io/netmiko/docs/netmiko/base_connection.html#netmiko.base_connection.BaseConnection.send_command
In their documentation, they say that use_textfsm
is a boolean (True or False) and it defaults to False. So your string '~/ntc-templates/ntc_templates/templates/cisco_ios_show_interface_transceiver.textfsm'
that you have there is only being read as "True". I think what you meant was:
use_textfsm='~/ntc-templates/ntc_templates/templates/cisco_ios_show_interface_transceiver.textfsm') | |
transceiver_output = connection.send_command( | |
'show interface transceiver', | |
read_timeout=90, | |
use_textfsm=True, | |
textfsm_template= '~/ntc-templates/ntc_templates/templates/cisco_ios_show_interface_transceiver.textfsm' | |
) |
connection = netmiko.ConnectHandler(host=host, device_type='cisco_ios', username=username, | ||
password=password, secret=password) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
connection = netmiko.ConnectHandler(host=host, device_type='cisco_ios', username=username, | |
password=password, secret=password) | |
connection = netmiko.ConnectHandler( | |
host=host, | |
device_type='cisco_ios', | |
username=username, | |
password=password, | |
secret=password | |
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this one i was lazy, i did this way on the test but didn't change here
when first writing script/code for me straight line felt easier
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All in one line is fine if it fits and you like it. My team uses 120 character as the maximum line length, as a guide for "fits on one line"
password=password, secret=password) | ||
connection.send_command('terminal length 0') | ||
connection.enable() | ||
except Exception as e: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's considered poor form to catch Exception, you should always be as explicit as possible here so you don't accidentally swallow an error you didn't mean to.
It looks like ConnectHandler and enable could raise ValueError, send_command can raise ReadTimeout. You could replace except Exception
with except ValueError, ReadTimeout
, or you could catch them separately, depending on whether you want to take the same action for all possible failures. For example, perhaps a ReadTimeout could be a network issue and you want to retry once before giving up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
my idea was to have the device and error shown, which i could later come back and check the error from the output and try is later.
but yeah its a good idea to have it retry depending on the error! noted!
## I know i could make a main function and invoke others but im still going through it in my learning path lol | ||
## Also should use a more structured start for the script using main or other way. No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both of these are true statements :P
Also, by convention, every python script/file should end in a blank line. The reason for it is "old technology", it's a throwback to when most people used a terminal. when you cat
the python file, having a blank line at the end of the file makes it a little easier to read. But either way it's a standard that pretty much everyone does, and many linters will enforce it.
Which brings me to Linters. You should install one. A linter is a script that will go through your code and clean it up. Depending on your settings it can do thins like make sure you always use the same quotes (python doesn't care if you use 'single' or "double" quotes, but it's generally expected that you will pick one and stick with it) and it can make sure you have the right number of blank lines before a method or class, etc. most of those things they can even fix for you magically, so you just run the command and it makes your code pretty. my team uses ruff
for most things: https://beta.ruff.rs/docs/tutorial/
file = open(r'/home/segattod/segattod-workspace/src/Segattod-package/myproject/Light_level_checks/list.txt', | ||
'r') | ||
file = file.read().splitlines() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is generally a bad idea. below you used the with
context manager like this:
with open(file, "r"):
stuff....
And that is the "right" way. One of the main problems with this way here is that you never closed the file. If someone else tried to open that file even if you aren't currently running your script, they could run into errors because it's locked by you. The operating system should eventually realize your script is done and eventually unlock it, but it's a bad idea to cross your fingers and hope.
The context manager magically closes the file when the code leaves the manager (hits the unindent) so that is never an issue.
Which generally also means it should be inside a function or method. But you already know that :P
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually didn't know it was a best practice just felt right to move it to a variable and work with that after(LOL)
You mentioned "the context manager magically closes .." do you mean the way i did it, is good, it will always close automatically after "moving" the content to the variable, right?
just confirming if it go it right lol
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You used a context manager the second time, down when you saved the data.
This is a context manager:
with open(file, mode) as file:
do_stuff()
do_more_stuff()
After do_stuff(), the manager will close the file before moving on to do_more_stuff().
## I know I could have used "return" but when i did it it was not "appending" | ||
## it was adding all for one device and erasing and add the new ones, should be simple mistake from my end but i could not figure lol |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nah, using append is perfectly fine here. I suspect the reason it was overwriting is because append()
returns None. if you wanted this to return a value then it should return (host, (sfp['iface']), pwr, state, model, speed)
and below where you call it, it would be something like formatted_data.append(light_level_check(connection))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't roll back to what i did to confirm, but i do believe it did exactly what you suggested,but if you think the way it is, looks good and not like a "remediate way to make it work" then should be fine ;)
I added a file called Click on "files changed" at the top to see it. |
Figured I'd try this as a way to comment on your code without getting too confusing. I'll make some changes and upload that as a separate file so you can see how I might have done it.
Overall, mostly just style suggestions.