Skip to content

Commit 26fa0da

Browse files
authored
Merge pull request CiscoDevNet#89 from gregbo/patch-1
Multiple improvements to support arguments and a more secure way to get the password.
2 parents 0f10a10 + 9c03a99 commit 26fa0da

File tree

1 file changed

+80
-53
lines changed

1 file changed

+80
-53
lines changed

restconf_update_ipaddress/updateip.py

Lines changed: 80 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
This script has been tested with Python 3.5, however may work with other versions.
1212
1313
This script targets the RESTCONF DevNet Sandbox that leverages a CSR1000v as
14-
a target. To execute this script against a different device, update the variables
15-
that list the connectivity, management interface, and url_base for RESTCONF.
14+
a target. To execute this script against a different device, update the
15+
variables and command-line arguments that list the connectivity, management
16+
interface, and url_base for RESTCONF.
1617
1718
Requirements:
1819
Python
@@ -24,51 +25,42 @@
2425
import json
2526
import requests
2627
import sys
28+
import os
2729
from argparse import ArgumentParser
2830
from collections import OrderedDict
31+
from getpass import getpass
2932
import urllib3
3033

3134
# Disable SSL Warnings
3235
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
3336

34-
35-
# These variables target the RESTCONF Always-On Sandbox hosted by Cisco DevNet
36-
HOST = 'ios-xe-mgmt.cisco.com'
37-
PORT = '443'
38-
USER = 'root'
39-
PASS = 'D_Vay!_10&'
40-
41-
# Identifies the interface on the device used for management access
42-
# Used to ensure the script isn't used to update the IP leveraged to manage device
43-
MANAGEMENT_INTERFACE = "GigabitEthernet1"
44-
45-
# Create the base URL for RESTCONF calls
46-
url_base = "https://{h}:{p}/restconf".format(h=HOST, p=PORT)
47-
4837
# Identify yang+json as the data formats
4938
headers = {'Content-Type': 'application/yang-data+json',
5039
'Accept': 'application/yang-data+json'}
5140

5241

5342
# Function to retrieve the list of interfaces on a device
54-
def get_configured_interfaces():
55-
url = url_base + "/data/ietf-interfaces:interfaces"
56-
43+
def get_configured_interfaces(url_base, username, password):
5744
# this statement performs a GET on the specified url
58-
response = requests.get(url,
59-
auth=(USER, PASS),
60-
headers=headers,
61-
verify=False
62-
)
45+
try:
46+
response = requests.get(url_base,
47+
auth=(username, password),
48+
headers=headers,
49+
verify=False
50+
)
51+
response.raise_for_status()
52+
except Exception as e:
53+
print(e, file=sys.stderr)
54+
sys.exit(1)
6355

6456
# return the json as text
6557
return response.json()["ietf-interfaces:interfaces"]["interface"]
6658

6759

6860
# Used to configure the IP address on an interface
69-
def configure_ip_address(interface, ip):
61+
def configure_ip_address(url_base, interface, ip, username, password):
7062
# RESTCONF URL for specific interface
71-
url = url_base + "/data/ietf-interfaces:interfaces/interface={i}".format(i=interface)
63+
url = url_base + "/interface={i}".format(i=interface)
7264

7365
# Create the data payload to reconfigure IP address
7466
# Need to use OrderedDicts to maintain the order of elements
@@ -89,32 +81,43 @@ def configure_ip_address(interface, ip):
8981
)])
9082

9183
# Use PUT request to update data
92-
response = requests.put(url,
93-
auth=(USER, PASS),
94-
headers=headers,
95-
verify=False,
96-
json=data
97-
)
84+
try:
85+
response = requests.put(url,
86+
auth=(username, password),
87+
headers=headers,
88+
verify=False,
89+
json=data
90+
)
91+
response.raise_for_status()
92+
except Exception as e:
93+
print(e, file=sys.stderr)
94+
sys.exit(1)
95+
9896
print(response.text)
9997

10098

10199
# Retrieve and print the current configuration of an interface
102-
def print_interface_details(interface):
103-
url = url_base + "/data/ietf-interfaces:interfaces/interface={i}".format(i=interface)
100+
def print_interface_details(url_base, interface, username, password):
101+
url = url_base + "/interface={i}".format(i=interface)
104102

105103
# this statement performs a GET on the specified url
106-
response = requests.get(url,
107-
auth=(USER, PASS),
108-
headers=headers,
109-
verify=False
110-
)
104+
try:
105+
response = requests.get(url,
106+
auth=(username, password),
107+
headers=headers,
108+
verify=False
109+
)
110+
response.raise_for_status()
111+
except Exception as e:
112+
print(e, file=sys.stderr)
113+
sys.exit(1)
111114

112115
intf = response.json()["ietf-interfaces:interface"]
113116
# return the json as text
114-
print("Name: ", intf["name"])
117+
print("Name: ", intf[0]["name"])
115118
try:
116-
print("IP Address: ", intf["ietf-ip:ipv4"]["address"][0]["ip"], "/",
117-
intf["ietf-ip:ipv4"]["address"][0]["netmask"])
119+
print("IP Address: ", intf[0]["ietf-ip:ipv4"]["address"][0]["ip"], "/",
120+
intf[0]["ietf-ip:ipv4"]["address"][0]["netmask"])
118121
except KeyError:
119122
print("IP Address: UNCONFIGURED")
120123
print()
@@ -124,15 +127,15 @@ def print_interface_details(interface):
124127

125128
# Ask the user to select an interface to configure. Ensures input is valid and
126129
# NOT the management interface
127-
def interface_selection(interfaces):
130+
def interface_selection(interfaces, mgmt_if):
128131
# Ask User which interface to configure
129132
sel = input("Which Interface do you want to configure? ")
130133

131134
# Validate interface input
132135
# Must be an interface on the device AND NOT be the Management Interface
133-
while sel == MANAGEMENT_INTERFACE or not sel in [intf["name"] for intf in interfaces]:
136+
while sel == mgmt_if or not sel in [intf["name"] for intf in interfaces]:
134137
print("INVALID: Select an available interface.")
135-
print(" " + MANAGEMENT_INTERFACE + " is used for management.")
138+
print(" " + mgmt_if + " is used for management.")
136139
print(" Choose another Interface")
137140
sel = input("Which Interface do you want to configure? ")
138141

@@ -149,13 +152,36 @@ def get_ip_info():
149152

150153

151154
def main():
152-
global do_input
153-
154155
"""
155156
Simple main method calling our function.
156157
"""
158+
159+
parser = ArgumentParser(
160+
prog=sys.argv[0], description='RESTCONF interface management tool')
161+
parser.add_argument('--hostname', '-a', type=str,
162+
help='sandbox hostname or IP address',
163+
default='ios-xe-mgmt.cisco.com')
164+
parser.add_argument('--username', '-u', type=str,
165+
help='sandbox username', default='developer')
166+
# Identifies the interface on the device used for management access
167+
# Used to ensure the script isn't used to update the IP leveraged to manage
168+
# device
169+
parser.add_argument('--management_if', '-m', type=str,
170+
help='management interface', default='GigabitEthernet1')
171+
parser.add_argument('--port', '-P', type=int,
172+
help='sandbox web port', default=443)
173+
args = parser.parse_args()
174+
175+
password = os.getenv('DEVNET_RESTCONF_PASSWORD')
176+
if password is None:
177+
password = getpass()
178+
179+
# Create the base URL for RESTCONF calls
180+
181+
url_base = "https://{h}:{p}/restconf/data/ietf-interfaces:interfaces".format(h=args.hostname, p=args.port)
182+
157183
# Get a List of Interfaces
158-
interfaces = get_configured_interfaces()
184+
interfaces = get_configured_interfaces(url_base, args.username, password)
159185

160186
print("The router has the following interfaces: \n")
161187
for interface in interfaces:
@@ -164,23 +190,24 @@ def main():
164190
print("")
165191

166192
# Ask User which interface to configure
167-
selected_interface = interface_selection(interfaces)
193+
selected_interface = interface_selection(interfaces, args.management_if)
168194
print(selected_interface)
169195

170196
# Print Starting Interface Details
171197
print("Starting Interface Configuration")
172-
print_interface_details(selected_interface)
198+
print_interface_details(url_base, selected_interface, args.username,
199+
password)
173200

174201
# As User for IP Address to set
175202
ip = get_ip_info()
176203

177204
# Configure interface
178-
configure_ip_address(selected_interface, ip)
205+
configure_ip_address(url_base, selected_interface, ip, args.username, password)
179206

180207
# Print Ending Interface Details
181208
print("Ending Interface Configuration")
182-
print_interface_details(selected_interface)
183-
209+
print_interface_details(url_base, selected_interface, args.username,
210+
password)
184211

185212
if __name__ == '__main__':
186213
sys.exit(main())

0 commit comments

Comments
 (0)