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

Annotation of /py-apic-em/py-apic-em.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 20372 - (hide 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 jclarke 20274 #!/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 jclarke 20372 if res.status_code > 299:
101 jclarke 20274 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 jclarke 20277 print " IP address: " + str(intf['ipv4Address']) + " / " + str(intf['ipv4Mask'])

Properties

Name Value
svn:executable

  ViewVC Help
Powered by ViewVC 1.1.27