/[marcuscom]/py-apic-em/py-apic-em.py
ViewVC logotype

Contents of /py-apic-em/py-apic-em.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 20372 - (show annotations) (download) (as text)
Sat Aug 20 15:21:37 2016 UTC (3 years, 5 months ago) by jclarke
File MIME type: text/x-python
File size: 9441 byte(s)
Be more permissive about return codes.

1 #!/usr/bin/env python
2 #-
3 # Copyright (c) 2015 Joe Clarke <jclarke@cisco.com>
4 # All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 # 1. Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
11 # 2. Redistributions in binary form must reproduce the above copyright
12 # notice, this list of conditions and the following disclaimer in the
13 # documentation and/or other materials provided with the distribution.
14 #
15 # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 #
25 # $MCom$
26
27 import sys
28 import re
29 import requests
30 from requests import Request, Session
31 import json
32 import urllib
33 import time
34 import paramiko
35 import sqlite3
36 import calendar
37 import time
38 import argparse
39
40 DEBUG = 0
41 REST_TIMEOUT = 300
42 REST_RETRY_INTERVAL = 1
43 REST_RETRIES = 3
44 REST_PAGE_LIMIT = 500
45 SSH_TIMEOUT = 60
46
47 class ApicEm:
48 pass
49
50 class RestError:
51 code = -1
52 msg = ""
53
54 def set_code(self, code):
55 self.code = code
56
57 def set_msg(self, msg):
58 self.msg = msg
59
60 def get_code(self):
61 return self.code
62
63 def get_msg(self):
64 return self.msg
65
66 def fetch_url(url, error, p=False, timeout=REST_TIMEOUT):
67 global DEBUG
68
69 s = Session()
70 requests.packages.urllib3.disable_warnings()
71 req = 'GET'
72 data = {}
73 headers = {}
74
75 if 'get' in p:
76 url += '?' + urllib.urlencode(p['get'])
77 if 'post' in p:
78 req = 'POST'
79 data = p['post']
80 if 'put' in p:
81 req = 'PUT'
82 if 'header' not in p:
83 p['header'] = {}
84 p['header']['Content-Length'] = len(p['put'])
85 data = p['put']
86 if 'header' in p:
87 headers = p['header']
88
89 req = Request(req, url, data=data, headers=headers)
90 ph = req.prepare()
91
92 if DEBUG > 0:
93 print "DEBUG: Headers = "
94 for h in ph.headers:
95 print " " + h + " : " + ph.headers[h]
96 print "DEBUG: Body = " + str(ph.body)
97
98 res = s.send(ph, verify=False, timeout=timeout)
99
100 if res.status_code > 299:
101 if DEBUG > 0:
102 print "DEBUG: The server returned code: " + str(res.status_code) + " response: " + res.text
103 print "DEBUG: Response Headers: "
104 for h in res.headers:
105 print " " + h + " : " + res.headers[h]
106 error.set_code(res.status_code)
107 j = res.json()
108 error.set_msg(j['response']['message'])
109 return None
110 else:
111 return res.text
112
113 def get_ticket(host, user, password, error):
114 global REST_RETRIES, REST_RETRY_INTERVAL
115
116 url = "https://" + host + "/api/v1/ticket"
117 p = {}
118
119 p['post'] = json.dumps({"username":user,"password":password})
120 p['header'] = {"Content-Type":"application/json"}
121
122 i = 0
123 res = None
124 while i < REST_RETRIES:
125 res = fetch_url(url, error, p)
126 if res is not None:
127 break
128 time.sleep(REST_RETRY_INTERVAL)
129 i = i + 1
130 if res is not None:
131 j = json.loads(res)
132 return j['response']['serviceTicket']
133
134 return None
135
136
137 def get_devices(host, ticket, error):
138 global REST_RETRIES, REST_RETRY_INTERVAL
139
140 url = "https://" + host + "/api/v1/network-device"
141 p = {}
142
143 p['header'] = {"X-Auth-Token":ticket}
144
145 i = 0
146 res = None
147 while i < REST_RETRIES:
148 res = fetch_url(url, error, p)
149 if res is not None:
150 break
151 time.sleep(REST_RETRY_INTERVAL)
152 i = i + 1
153 if res is not None:
154 j = json.loads(res)
155 return j['response']
156
157 return None
158
159 def get_interface_count(host, ticket, devid, error):
160 global REST_RETRIES, REST_RETRY_INTERVAL
161
162 url = "https://" + host + "/api/v1/interface/network-device/" + devid + "/count"
163 p = {}
164 p['header'] = {"X-Auth-Token":ticket}
165
166 i = 0
167 res = None
168 while i < REST_RETRIES:
169 res = fetch_url(url, error, p)
170 if res is not None:
171 break
172 time.sleep(REST_RETRY_INTERVAL)
173 i = i + 1
174 if res is not None:
175 j = json.loads(res)
176 return j['response']
177
178 return None
179
180 def get_interfaces(host, ticket, devid, error):
181 global REST_RETRIES, REST_RETRY_INTERVAL, REST_PAGE_LIMIT
182
183 url = "https://" + host + "/api/v1/interface/network-device/" + devid
184 p = {}
185 p['header'] = {"X-Auth-Token":ticket}
186
187 count = get_interface_count(host, ticket, devid, error)
188 if count is None:
189 return None
190
191 offset = 1
192 limit = REST_PAGE_LIMIT
193 intfs = []
194 while True:
195 iurl = url
196 iurl += "/" + str(offset) + "/" + str(limit)
197
198 i = 0
199 res = None
200 while i < REST_RETRIES:
201 res = fetch_url(iurl, error, p)
202 if res is not None:
203 break
204 time.sleep(REST_RETRY_INTERVAL)
205 i = i + 1
206 if res is not None:
207 j = json.loads(res)
208 intfs.extend(j['response'])
209
210 offset = offset + limit
211 if offset + limit >= count:
212 break
213
214 return intfs
215
216 def get_device_count(host, ticket, error):
217 global REST_RETRIES, REST_RETRY_INTERVAL
218
219 url = "https://" + host + "/api/v1/network-device/count"
220 p = {}
221 p['header'] = {"X-Auth-Token":ticket}
222
223 i = 0
224 res = None
225 while i < REST_RETRIES:
226 res = fetch_url(url, error, p)
227 if res is not None:
228 break
229 time.sleep(REST_RETRY_INTERVAL)
230 i = i + 1
231 if res is not None:
232 j = json.loads(res)
233 return j['response']
234
235 return None
236
237 def get_device_creds(host, ticket, devid, error):
238 global REST_RETRIES, REST_RETRY_INTERVAL
239
240 url = "https://" + host + "/api/v1/network-device/management-info"
241 p = {}
242 p['header'] = {"X-Auth-Token":ticket}
243
244 count = get_device_count(host, ticket, error)
245 if count is None:
246 return None
247
248 offset = 1
249 limit = REST_PAGE_LIMIT
250 p['get'] = {}
251 while True:
252 p['get']['offset'] = offset
253 p['get']['limit'] = limit
254
255 i = 0
256 res = None
257 while i < REST_RETRIES:
258 res = fetch_url(url, error, p)
259 if res is not None:
260 break
261 time.sleep(REST_RETRY_INTERVAL)
262 i = i + 1
263 if res is not None:
264 j = json.loads(res)
265 minfo = j['response']['networkDeviceManagementInfo']
266 marr = []
267 marr.extend(minfo)
268 for dev in marr:
269 if dev['id'] == devid:
270 if 'cli_transport' in dev['credentials']:
271 if dev['credentials']['cli_transport'] != 'ssh2':
272 error.set_msg("Transport is not 'ssh2'")
273 return None
274 if 'cli_enable_password' in dev:
275 return (dev['credentials']['cli_login_username'], dev['credentials']['cli_login_password'], dev['credentials']['cli_enable_password'])
276 else:
277 return (dev['credentials']['cli_login_username'], dev['credentials']['cli_login_password'], "")
278 else:
279 error.set_msg("No cli credentials found for device")
280 return None
281 offset = offset + limit
282 if offset + limit >= count:
283 break
284
285 return None
286
287 if __name__ == '__main__':
288 error = RestError()
289 apic = ApicEm()
290 parser = argparse.ArgumentParser(prog='py-apic-em.py', description='APIC-EM API test script.')
291 parser.add_argument('--apic-em-hostname', '-H', dest='apic_em', metavar='<HOSTNAME>', help='Hostname of the APIC-EM controller', required=True)
292 parser.add_argument('--apic-em-username', '-U', dest='username', metavar='<USERNAME>', help='APIC-EM API username', required=True)
293 parser.add_argument('--apic-em-password', '-P', dest='password', metavar='<PASSWORD>', help='APIC-EM API password', required=True)
294 parser.parse_args(namespace=apic)
295 ticket = get_ticket(apic.apic_em, apic.username, apic.password, error)
296 if ticket is None:
297 print "Error obtaining RBAC ticket: " + error.get_msg()
298 sys.exit(1)
299 devs = get_devices(apic.apic_em, ticket, error)
300 if devs is None:
301 print "Error retrieving devices: " + error.get_msg()
302 sys.exit(1)
303 for dev in devs:
304 intfs = get_interfaces(apic.apic_em, ticket, dev['id'], error)
305 if intfs is None:
306 print "Error retrieving interfaces for " + dev['hostname'] + ": " + error.get_msg()
307 continue
308 print "Device: " + dev['hostname'] + ": "
309 for intf in intfs:
310 print " Name : " + str(intf['portName'])
311 print " IP address: " + str(intf['ipv4Address']) + " / " + str(intf['ipv4Mask'])

Properties

Name Value
svn:executable

  ViewVC Help
Powered by ViewVC 1.1.27