1
\$\begingroup\$

I wrote this script to add some config to a Juniper device. It works well but the whole user input validation section (yes or no section) seems a little messy.

Is there a better way I could have done it?

from jnpr.junos import Device
from jnpr.junos.utils.config import Config
import getpass

#Grab credentials
username = raw_input("Enter your username:")
password = getpass.getpass("Enter your password:")

#Confirmation of commands
commands = open("commands" , "r")
commands_to_commit = commands.read()
print ""
print "The commands you are about to commit are: "
print commands_to_commit
print ""
print "Do you want to continue to run these commands?"
confirm = raw_input("Y or N: ")
    if confirm in ['n','no','N','NO','No']:
            print "Exiting..."
            quit()
while confirm not in ['y','Y','yes',"Yes",'YES','n','N','NO','No','no']:
    print "Invalid Choice, Try again"
    confirm = raw_input("Y or N: ")
    if confirm in ['n','no','N','NO','No']:
            print "Exiting..."
            quit()
    elif confirm in ['y','Y','yes',"Yes",'YES']:
            continue

#Open a file called swichlist which has a list of devices to modify
with open('switchlist') as infile:
    for host in infile:
            try:
                    print "Working on:", host,
                    #Connect to devices in switchlist
                    dev = Device(host=host.strip(),  user=username, password=password)
                    dev.open()
                    cu = Config(dev)
                    #Looks for a file named commands with the list of commands to run
                    incmd = open('commands')
                    set_cmd = incmd.read()
                    cu.load(set_cmd, format="set")
                    cu.commit()
                    dev.close()
                    print "Completed:", host
            except Exception,e: print "Error:", e
            continue
\$\endgroup\$

migrated from stackoverflow.com Jul 29 '15 at 17:28

This question came from our site for professional and enthusiast programmers.

  • \$\begingroup\$ Please correct your indentation. The code is technically broken as posted in Rev 1. \$\endgroup\$ – 200_success Jul 29 '15 at 17:47
1
\$\begingroup\$

The confirmation prompt is a self-contained chunk of code with a specific purpose. It deserves to be extracted into a function:

def confirm(prompt='Y or N: ', yes='YES', no='NO'):
    while True:
        response = raw_input(prompt).upper()
        if yes.startswith(response) and not no.startswith(response):
            return True
        elif no.startswith(response) and not yes.startswith(response):
            return False
        print "Invalid choice. Try again."

(Technically, this is more lenient than your original code, in that it accepts strings like 'yE' as a yes. I think that's OK.)

Then, in your main program, you can write:

print "Do you want to continue to run these commands?"
if not confirm():
    print "Exiting..."
    quit()

Any call to open() should almost certainly be done using a with block. You wrote with open('switchlist') as infile, which is good. However, you also wrote commands = open("commands", "r") and incmd = open('commands'), neither of which you close properly. But why are you calling incmd = open('commands') at all, when it's just supposed to be commands_to_commit?

\$\endgroup\$
  • 2
    \$\begingroup\$ If you allow any string for yes and no, you should reject an answer which is a prefix of the longest common prefix among yes and no (and any other valid answer). Example, if yes='fantastic' and no='false', the longest common prefix is 'fa', and any answer prefix of this (namely 'f' and 'fa') is ambiguous, but your code will treat it as a yes answer. \$\endgroup\$ – fferri Jul 29 '15 at 20:52
  • 2
    \$\begingroup\$ Also note that for any string s, s.startswith('') is always true, so you treat also the empty answer as yes. \$\endgroup\$ – fferri Jul 29 '15 at 20:53
0
\$\begingroup\$

If you .lower() the input you have to match it against less patterns. Also a single while loop can handle all the input validation stuff.

while True: # repeat until input is not valid
    confirm = raw_input("Y or N: ").lower()
    if confirm in ('y', 'yes', 'n', 'no'): break
    else: print "Invalid Choice, Try again"

if confirm in ('n', 'no'):
    print "Exiting..."
    quit()
\$\endgroup\$
0
\$\begingroup\$

You can get rid of the first:

confirm = raw_input("Y or N: ").lower()
if confirm in ['n', 'no']:
    print "Exiting..."
    quit()

right off the bat. Just initialize confirm to ''and it'll kick you into the while loop.

You can also move the 'switchlist' and 'commands' filenames to variables so they aren't hard coded. Ideally, you should move them to a config file or cli args.

Below is the updated/cleaned up version of your code:

from jnpr.junos import Device
from jnpr.junos.utils.config import Config
import getpass

commands_filename = 'commands'
switchlist_filename = 'switchlist'

# Grab credentials
username = raw_input('Enter your username:')
password = getpass.getpass('Enter your password:')

# Confirmation of commands
commands_to_commit = open(commands_filename, 'r').read()

print ''
print 'The commands you are about to commit are: '
print commands_to_commit
print ''
print 'Do you want to continue to run these commands?'

confirm = ''
while confirm not in ['y', 'ye', 'yes', 'n', 'no']:
    confirm = raw_input('Y or N: ').lower()
    if confirm in ['n', 'no']:
        print 'Exiting...'
        quit()
    elif confirm in ['y', 'ye', 'yes']:
        continue
    else:
        print 'Invalid choice, try again'

# Open a file called swichlist which has a list of devices to modify
with open(switchlist_filename) as infile:
    for host in infile:
        try:
            print 'Working on: ', host

            # Connect to devices in switchlist
            dev = Device(host=host.strip(),  user=username, password=password)
            dev.open()
            cu = Config(dev)

            # Looks for a file named commands with the list of commands to run
            set_cmd = open(commands_filename).read()
            cu.load(set_cmd, format='set')
            cu.commit()
            dev.close()

            print 'Completed: ', host
        except Exception,e: 
            print 'Exception: ', str(e)
            continue
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.