blob: e069ee3e595b57a949a5ff5c89313cfb5ccb3bb5 [file] [log] [blame]
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -08001#
2# Copyright (c) 2012,2013 Big Switch Networks, Inc.
3#
4# Licensed under the Eclipse Public License, Version 1.0 (the
5# "License"); you may not use this file except in compliance with the
6# License. You may obtain a copy of the License at
7#
8# http://www.eclipse.org/legal/epl-v10.html
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13# implied. See the License for the specific language governing
14# permissions and limitations under the License.
15#
16
17import collections
18import urllib
19import error
20import json
21import modi
22import utif
23import url_cache
24
25#
26# json based on non model based query
27#
28
29def rest_to_model_init(bs, modi):
30 global sdnsh, mi
31
32 sdnsh = bs
33 mi = modi
34
35#
36# --------------------------------------------------------------------------------
37
38def check_rest_result(result, message = None):
39 if isinstance(result, collections.Mapping):
40 error_type = result.get('error_type')
41 if error_type:
42 raise error.CommandRestError(result, message)
43
44
45#
46# --------------------------------------------------------------------------------
47
48def get_model_from_url(obj_type, data):
49 """
50 Intended to be used as a conversion tool, to provide a way
51 to move model requests to specific url requests
52 """
53
54 onos = 1
55 startswith = '__startswith'
56 data = dict(data)
57
58 if mi.obj_type_has_model(obj_type):
59 print "MODEL_URL: %s not supported" % obj_type
60 return []
61 #
62 # save sort field
63 sort = data.get('orderby', None)
64 if sort:
65 del data['orderby']
66
67 obj_type_url = mi.obj_type_has_url(obj_type)
68 url = "http://%s/rest/v1/" % sdnsh.controller + obj_type_url
69
70 # for the devices query, be sensitive to the types of queries
71 # since the devices query doesn't understand the relationship
72 # between the vlan=='' for address_space == 'default'.
73 if obj_type_url == 'device':
74 if 'vlan' in data and data['vlan'] == '':
75 del data['vlan']
76
77 # data items need to be included into the query.
78 if data:
79 url += '?'
80 url += urllib.urlencode(data)
81 if sdnsh.description: # description debugging
82 print "get_model_from_url: request ", obj_type, data, url
83 #
84 # cache small, short time results
85 entries = url_cache.get_cached_url(url)
86 if entries != None:
87 if sdnsh.description: # description debugging
88 print 'get_model_from_url: using cached result for ', url
89 else:
90 try:
91 result = sdnsh.store.rest_simple_request(url)
92 check_rest_result(result)
93 entries = json.loads(result)
94 except Exception, e:
95 if sdnsh.description: # description debugging
96 print "get_model_from_url: failed request %s: '%s'" % (url, e)
97 entries = []
98
99 url_cache.save_url(url, entries)
100
101 key = mi.pk(obj_type)
102
103 # convert specific types XXX need better generic mechanism
104 result = []
105 if obj_type == 'host-attachment-point':
106 for entry in entries:
107 # it is possible for multiple mac's to appear here
108 # as long as a single ip is associated with the device.
109 if len(entry['mac']) > 1:
110 raise error.CommandInternalError("host (attachment point): >1 mac")
111 mac = entry['mac'][0]
112 aps = entry['attachmentPoint']
113 lastseen = entry['lastSeen']
114 for ap in aps:
115 status = ap.get('errorStatus', '')
116 if status == None:
117 status = ''
118 if len(entry['vlan']) == 0:
119 result.append({'id' : mac + '|' + ap['switchDPID'] +
120 '|' + str(ap['port']),
121 'mac' : mac,
122 'switch' : ap['switchDPID'],
123 'ingress-port' : ap['port'],
124 'status' : status,
125 'last-seen' : lastseen,
126 'address-space': entry['entityClass'],
127 })
128 else:
129 for vlan in entry['vlan']:
130 result.append({'id' : mac + '|' + ap['switchDPID'] +
131 '|' + str(ap['port']),
132 'mac' : mac,
133 'vlan' : vlan,
134 'switch' : ap['switchDPID'],
135 'ingress-port' : ap['port'],
136 'status' : status,
137 'last-seen' : lastseen,
138 'address-space': entry['entityClass'],
139 })
140 elif obj_type == 'host-network-address':
141
142 for entry in entries:
143 if len(entry['mac']) > 1:
144 raise error.CommandInternalError("host (network-address): >1 mac")
145 mac = entry['mac'][0]
146 ips = entry['ipv4']
147 lastseen = entry['lastSeen']
148 for ip in ips:
149 if len(entry['vlan']) == 0:
150 result.append({'id' : mac + '|' + ip,
151 'mac' : mac,
152 'ip-address' : ip,
153 'address-space' : entry['entityClass'],
154 'last-seen' : lastseen })
155 else:
156 for vlan in entry['vlan']:
157 result.append({'id' : mac + '|' + ip,
158 'mac' : mac,
159 'vlan' : vlan,
160 'ip-address' : ip,
161 'address-space' : entry['entityClass'],
162 'last-seen' : lastseen })
163 elif obj_type == 'host':
164 # For host queries, the device manager returns 'devices' which
165 # match specific criteria, for example, if you say ipv4 == 'xxx',
166 # the device which matches that criteris is returned. However,
167 # there may be multiple ip addresses associated.
168 #
169 # this means that two different groups of values for these
170 # entities are returned. fields like 'ipv4' is the collection
171 # of matching values, while 'ips' is the complee list.
172 # 'switch', 'port' are the match values, while 'attachment-points'
173 # is the complete list.
174 #
175
176 ip_match = data.get('ipv4')
177 ip_prefix = data.get('ipv4__startswith')
178
179 dpid_match = data.get('dpid')
180 dpid_prefix = data.get('dpid__startswith')
181
182 port_match = data.get('port')
183 port_prefix = data.get('port__startswith')
184
185 address_space_match = data.get('address-space')
186 address_space_prefix = data.get('address-space__startswith')
187
Srikanth Vavilapallica79f962015-04-01 18:48:05 -0700188 if onos == 2:
189 entries = entries['hosts']
190
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -0800191 for entry in entries:
192 if onos==0:
193 if len(entry['mac']) > 1:
194 raise error.CommandInternalError("host: >1 mac")
195 mac = entry['mac'][0]
196 lastseen = entry['lastSeen']
Srikanth Vavilapallica79f962015-04-01 18:48:05 -0700197 elif onos==1:
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -0800198 mac = entry['mac']
199 lastseen = 0
Srikanth Vavilapallica79f962015-04-01 18:48:05 -0700200 hostid = '%s' % (mac)
201 elif onos==2:
202 mac = entry['mac']
203 hostid = entry['id']
204 lastseen = 0
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -0800205
Srikanth Vavilapallica79f962015-04-01 18:48:05 -0700206 ipFieldName = 'ipv4'
207 if onos == 2:
208 ipFieldName = 'ipAddresses'
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -0800209 ips = None
210 if not ip_match and not ip_prefix:
Srikanth Vavilapallica79f962015-04-01 18:48:05 -0700211 ipv4 = entry[ipFieldName]
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -0800212 elif ip_match:
Srikanth Vavilapallica79f962015-04-01 18:48:05 -0700213 ipv4 = [x for x in entry[ipFieldName] if x == ip_match]
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -0800214 elif ip_prefix:
Srikanth Vavilapallica79f962015-04-01 18:48:05 -0700215 ipv4 = [x for x in entry[ipFieldName] if x.startswith(ip_prefix)]
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -0800216
Srikanth Vavilapallica79f962015-04-01 18:48:05 -0700217 if len(entry[ipFieldName]):
218 ips = [{'ip-address' : x, 'last-seen' : lastseen}
219 for x in entry[ipFieldName] ]
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -0800220 aps = None
221 switch = []
222 port = []
223
224 #dpid_match = entry.get('dpid')
225 if onos == 0:
226 attachPoint = 'attachmentPoint'
227 attachDpid = 'switchDPID'
228 attachPort = 'port'
Srikanth Vavilapallica79f962015-04-01 18:48:05 -0700229 elif onos == 1:
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -0800230 attachPoint = 'attachmentPoints'
231 attachDpid = 'dpid'
232 attachPort = 'portNumber'
Srikanth Vavilapallica79f962015-04-01 18:48:05 -0700233 elif onos == 2:
234 attachPoint = 'location'
235 attachDpid = 'elementId'
236 attachPort = 'port'
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -0800237
Srikanth Vavilapallica79f962015-04-01 18:48:05 -0700238 if onos == 2:
239 aps = [{'switch' : entry[attachPoint][attachDpid],
240 'ingress-port' : entry[attachPoint][attachPort] }]
241 if not dpid_match and not dpid_prefix:
242 switch = [entry[attachPoint][attachDpid]]
243 elif dpid_match:
244 if entry[attachPoint][attachDpid] == dpid_match:
245 switch = [entry[attachPoint][attachDpid]]
246 elif dpid_prefix:
247 if entry[attachPoint][attachDpid].startswith(dpid_prefix):
248 switch = [entry[attachPoint][attachDpid]]
249
250 if not port_match and not port_prefix:
251 port = [entry[attachPoint][attachPort]]
252 elif port_match:
253 if entry[attachPoint][attachPort] == port_match:
254 port = [entry[attachPoint][attachPort]]
255 elif port_prefix:
256 if entry[attachPoint][attachPort].startswith(port_prefix):
257 port = [entry[attachPoint][attachPort]]
258 elif len(entry[attachPoint]):
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -0800259 aps = [{'switch' : x[attachDpid], 'ingress-port' : x[attachPort] }
260 for x in entry[attachPoint]]
261
262 if not dpid_match and not dpid_prefix:
263 switch = [x[attachDpid] for x in entry[attachPoint]]
264 elif dpid_match:
265 switch = [x[attachDpid] for x in entry[attachPoint]
266 if x[attachDpid] == dpid_match]
267 elif dpid_prefix:
268 switch = [x[attachDpid] for x in entry[attachPoint]
269 if x[attachDpid].startswith(dpid_prefix)]
270
271 if not port_match and not port_prefix:
272 port = [x[attachPort] for x in entry[attachPoint]]
273 elif port_match:
274 port = [x[attachPort] for x in entry[attachPoint]
275 if x[attachPort] == port_match]
276 elif port_prefix:
277 port = [x[attachPort] for x in entry[attachPoint]
278 if x[attachPort].startswith(port_prefix)]
279
280 if onos == 0:
281 address_space = entry['entityClass']
282 dhcp_client_name = entry.get('dhcpClientName', '')
283 if address_space_match and address_space != address_space_match:
284 continue
285 if address_space_prefix and not address_space.startswith(address_space_prefix):
286 continue
287
Srikanth Vavilapallica79f962015-04-01 18:48:05 -0700288 if (onos == 1) or (onos == 2):
289 result.append({'id' : hostid,
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -0800290 'mac' : mac,
291 'ips' : ips,
292 'ipv4' : ipv4,
293 'attachment-points' : aps,
294 'dpid' : switch,
295 'port' : port,
296 'last-seen' : 0})
297 else:
298 if len(entry['vlan']) == 0:
299 id = '%s||%s' % (address_space, mac)
300 result.append({'id' : id,
301 'mac' : mac,
302 'ips' : ips,
303 'ipv4' : ipv4,
304 'attachment-points' : aps,
305 'dpid' : switch,
306 'port' : port,
307 'address-space' : address_space,
308 'dhcp-client-name' : dhcp_client_name,
309 'last-seen' : lastseen})
310 else:
311 for vlan in entry['vlan']:
312 if address_space != 'default':
313 id = '%s||%s' % (address_space, mac)
314 else:
315 id = '%s|%s|%s' % (address_space, vlan, mac)
316 result.append({'id' : id,
317 'mac' : mac,
318 'vlan' : vlan,
319 'ips' : ips,
320 'ipv4' : ipv4,
321 'attachment-points' : aps,
322 'dpid' : switch,
323 'port' : port,
324 'address-space' : address_space,
325 'dhcp-client-name' : dhcp_client_name,
326 'last-seen' : lastseen})
327
328 # Also need to add hostConfig entries.
329 if not mi.obj_type_has_model('host-config'):
330 raise error.CommandInternalError("host-config: not served via model")
331 host_config = sdnsh.rest_query_objects('host-config', data)
332 if sdnsh.description: # description debugging
333 print "get_model_from_url: adding host-config ", data, host_config
334 known_ids = [x['id'] for x in result]
335
336 for hc in host_config:
337 id = hc['id']
338 if id not in known_ids:
339 # be sensitive to search fields:
340 query_match = True
341 if len(data):
342 for (d, dv) in data.items():
343 # other ops aside from '='?
344 if d.endswith(startswith):
345 fn = d[:-len(startswith)]
346 if not fn in hc or not hc[fn].startswith(dv):
347 query_match = False
348 elif (not d in hc) or dv != hc[d]:
349 query_match = False
350 break
351
352 if query_match:
353 hc['attachment-points'] = None
354 hc['dpid'] = None
355 hc['ips'] = None
356 hc['last-seen'] = None
357 result.append(hc)
358
359 elif obj_type == 'vns-interface':
360 for entry in entries:
361 vns = entry['parentVNS']['name']
362 rule = entry['parentRule']
363 rule_name = 'default'
364 if rule and 'name' in rule:
365 rule_name = rule['name']
366
367 result.append({ key : vns + '|' + entry['name'],
368 'vns' : vns,
369 'address-space' : entry['parentVNS']['addressSpaceName'],
370 'interface' : entry['name'],
371 'rule' : rule_name,
372 'last-seen' : entry['lastSeen'],
373 })
374
375 # also need to add vns-interface-config
376 if not mi.obj_type_has_model('vns-interface-config'):
377 raise error.CommandInternalError("vns-interface-config: not service via model")
378 vns_intf_config = sdnsh.rest_query_objects('vns-interface-config', data)
379 known_vns_intfs = [x[key] for x in result]
380 for vns_intf in vns_intf_config:
381 if not vns_intf[key] in known_vns_intfs:
382 vns_intf['rule'] = 'default'
383 result.append(vns_intf)
384
385 elif obj_type == 'host-vns-interface':
386
387 # mac matching works for the request
388
389 vns_match = data.get('vns')
390 vns_prefix = data.get('vns__startswith')
391
392 for entry in entries:
393 device = entry['device']
394 if len(device['mac']) > 1:
395 raise error.CommandInternalError("host (vns-interface): >1 mac")
396
397 device_last_seen = device['lastSeen']
398 address_space = device['entityClass']
399 mac = device['mac'][0] # currently, should only be one
400
401 ips = None
402 if len(device['ipv4']):
403 ips = [{'ip-address' : x, 'last-seen' : device_last_seen}
404 for x in device['ipv4'] ]
405
406 vlans = device.get('vlan', []) # currently, should only be one
407 if len(vlans) == 0: # iterate once when list is empty
408 vlans = [ '' ]
409
410 aps = None
411 if len(device['attachmentPoint']):
412 aps = [{'switch' : x['switchDPID'], 'ingress-port' : x['port'] }
413 for x in device['attachmentPoint']]
414
415 for iface in entry.get('iface', []):
416 vns = iface['parentVNS']['name']
417 last_seen = iface['lastSeen']
418 if vns_match and vns_match != vns:
419 continue
420 if vns_prefix and not vns.startswith(vns_prefix):
421 continue
422
423 for vlan in vlans: # there's supposed to only be at most one vlan.
424 if address_space != 'default' or type(vlan) != int:
425 host = '%s||%s' % (address_space, mac)
426 else:
427 host = '%s|%s|%s' % (address_space, vlan, mac)
428
429 result.append({key : mac + '|' + vns + '|' + iface['name'],
430 'host' : host,
431 'mac' : mac,
432 'vlan' : vlan,
433 'address-space' : address_space,
434 'ips' : ips,
435 'attachment-points' : aps,
436 'vns' : vns,
437 'interface' : vns + '|' + iface['name'],
438 'last-seen' : device_last_seen})
439 elif obj_type == 'switches':
440 switch_match = data.get('dpid')
441 switch_prefix = data.get('dpid__startswith')
442
Srikanth Vavilapalli59ddcde2015-03-10 14:40:38 -0700443 if onos == 1:
444 # this synthetic obj_type's name is 'switches' in an attempt
445 # to disabigutate it from 'class Switch'
446 #TODO: Need figure out a better way to get url (Through sdncon framework)
447 url = "http://%s/rest/v1/mastership" % sdnsh.controller
448 try:
449 result2 = sdnsh.store.rest_simple_request(url)
450 check_rest_result(result2)
451 mastership_data = json.loads(result2)
452 except Exception, e:
453 if sdnsh.description: # description debugging
454 print "get_model_from_url: failed request %s: '%s'" % (url, e)
455 entries = []
456 for entry in entries:
457 dpid = entry.get('dpid')
458 if(dpid in mastership_data.keys()):
459 #As there is only one master for switch
460 controller = mastership_data[dpid][0].get('controllerId')
461 else:
462 controller = None
463 if switch_match and switch_match != entry['dpid']:
464 continue
465 if switch_prefix and not entry['dpid'].startswith(switch_prefix):
466 continue
467 if onos == 1:
468 result.append({
469 'dpid' : entry['dpid'],
470 'switch-alias' : entry['stringAttributes']['name'],
471 'connected-since' : entry['stringAttributes']['ConnectedSince'],
472 'ip-address' : entry['stringAttributes']['remoteAddress'],
473 'type' : entry['stringAttributes']['type'],
474 'controller' : controller
475 })
476 else:
477 attrs = entry['attributes']
478 actions = entry['actions']
479 capabilities = entry['capabilities']
480 inet_address = entry.get('inetAddress')
481 ip_address = ''
482 tcp_port = ''
483 if inet_address:
484 # Current Java value looks like: /192.168.2.104:38420
485 inet_parts = inet_address.split(':')
486 ip_address = inet_parts[0][1:]
487 tcp_port = inet_parts[1]
488
489 result.append({
490 'dpid' : entry['dpid'],
491 'connected-since' : entry['connectedSince'],
492 'ip-address' : ip_address,
493 'tcp-port' : tcp_port,
494 'actions' : actions,
495 'capabilities' : capabilities,
496 'dp-desc' : attrs.get('DescriptionData', ''),
497 'fast-wildcards' : attrs.get('FastWildcards', ''),
498 'supports-nx-role' : attrs.get('supportsNxRole', ''),
499 'supports-ofpp-flood' : attrs.get('supportsOfppFlood', ''),
500 'supports-ofpp-table' : attrs.get('supportsOfppTable', ''),
501 'core-switch' : False,
502 })
503 elif onos == 2:
504 for entry in entries.get('devices'):
505 dpid = entry.get('id')
506 #if(dpid in mastership_data.keys()):
507 #As there is only one master for switch
508 # controller = mastership_data[dpid][0].get('controllerId')
509 #else:
510 # controller = None
511 if switch_match and switch_match != entry['id']:
512 continue
513 if switch_prefix and not entry['id'].startswith(switch_prefix):
514 continue
515 switchType = entry['mfr'] + '' + \
516 entry['hw'] + '' + entry['sw'] + '' + \
517 entry['annotations']['protocol']
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -0800518 result.append({
Srikanth Vavilapalli59ddcde2015-03-10 14:40:38 -0700519 'dpid' : entry['id'],
520 'switch-alias' : None,
521 'connected-since' : None,
522 'ip-address' : entry['annotations']['channelId'],
523 'type' : switchType,
524 'controller' : None
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -0800525 })
526 # now add switch-config
527
528 switch_config = sdnsh.rest_query_objects('switch-config', data)
529 known_dpids = dict([[x['dpid'], x] for x in result])
530
531 if onos == 0:
532 for sw in switch_config:
533 dpid = sw['dpid']
534 if not dpid in known_dpids:
535 # be sensitive to search fields:
536 query_match = True
537 if len(data):
538 for (d, dv) in data.items():
539 # other ops aside from '='?
540 if d.endswith(startswith):
541 fn = d[:-len(startswith)]
542 if not fn in sw or not sw[fn].startswith(dv):
543 query_match = False
544 elif (not d in sw) or dv != sw[d]:
545 query_match = False
546 break
547
548 if query_match:
549 sw['ip-address'] = ''
550 sw['tcp-port'] = ''
551 sw['connected-since'] = ''
552 result.append(sw)
553 [dpid].update(sw)
554 elif obj_type == 'interfaces':
555
556 # These are called interfaces because the primary
557 # key is constructed with the interface name, not
558 # the port number.
559
560 # the 'switches' query to sdnplatform currently
561 # doesn't support searching for the interface
562 # names. its done here instead
563
564 switch_match = data.get('dpid')
565 switch_prefix = data.get('dpid__startswith')
566
567 name_match = data.get('portName')
568 if name_match:
569 name_match = name_match.lower()
570 name_prefix = data.get('portName__startswith')
571 if name_prefix:
572 name_prefix = name_prefix.lower()
573
574 # this synthetic obj_type's name is 'switches' in an attempt
575 # to disabigutate it from 'class Switch'
Srikanth Vavilapallica79f962015-04-01 18:48:05 -0700576 if onos == 2:
577 entries = entries["devices"]
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -0800578 for entry in entries:
Srikanth Vavilapallica79f962015-04-01 18:48:05 -0700579 if onos == 2:
580 dpid = entry['id']
581 else:
582 dpid = entry['dpid']
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -0800583
584 if switch_match and switch_match != dpid:
585 continue
586 if switch_prefix and not dpid.startswith(switch_prefix):
587 continue
588
589 for p in entry['ports']:
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -0800590 if onos == 0:
Srikanth Vavilapallica79f962015-04-01 18:48:05 -0700591 portNumber = p['portNumber']
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -0800592 name = p['name']
Srikanth Vavilapallica79f962015-04-01 18:48:05 -0700593 state = p['state']
594 elif onos == 1:
595 portNumber = p['portNumber']
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -0800596 name = p['stringAttributes']['name']
Srikanth Vavilapallica79f962015-04-01 18:48:05 -0700597 state = p['state']
598 elif onos == 2:
599 portNumber = p['port']
600 if portNumber == 'local':
601 portNumber = 0
602 name = p['annotations']['portName']
603 if p['isEnabled'] == 'True':
604 state = 'up'
605 else:
606 state = 'down'
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -0800607
608 if name_match and name.lower() != name_match:
609 continue
610 if name_prefix and not name.lower().startswith(name_prefix):
611 continue
612 if onos == 0:
613 result.append({
614 'id' : '%s|%s' % (dpid,name),
615 'portNumber' : portNumber,
616 'switch' : dpid,
617 'portName' : p['name'],
618 'config' : p['config'],
Srikanth Vavilapallica79f962015-04-01 18:48:05 -0700619 'state' : state,
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -0800620 'advertisedFeatures' : p['advertisedFeatures'],
621 'currentFeatures' : p['currentFeatures'],
622 'hardwareAddress' : p['hardwareAddress'],
623 })
624 else:
625 result.append({
626 'id' : '%s|%s' % (dpid,name),
627 'portNumber' : portNumber,
628 'switch' : dpid,
629 'portName' : name,
630 'config' : 0,
Srikanth Vavilapallica79f962015-04-01 18:48:05 -0700631 'state' : state,
Srikanth Vavilapalli1725e492014-12-01 17:50:52 -0800632 'advertisedFeatures' : 0,
633 'currentFeatures' : 0,
634 'hardwareAddress' : 0,
635 })
636
637
638 #
639 # order the result
640 if sort:
641 if sort[0] == '-':
642 sort = sort[1:]
643 # decreasing
644 if sdnsh.description: # description debugging
645 print "get_model_from_url: order decreasing ", sort
646 result = sorted(result, key=lambda k:k.get(sort, ''),
647 cmp=lambda x,y : cmp(y,x))
648 else:
649 # increasing
650 if sdnsh.description: # description debugging
651 print "get_model_from_url: order increasing ", sort
652 result = sorted(result, key=lambda k:k.get(sort, ''),
653 cmp=lambda x,y : cmp(x,y))
654 else:
655 # use tail-integer on the entries
656 if sdnsh.description: # description debugging
657 print "get_model_from_url: pk ordering ", key
658 def sort_cmp(x,y):
659 for (idx, x_v) in enumerate(x):
660 c = cmp(utif.try_int(x_v), utif.try_int(y[idx]))
661 if c != 0:
662 return c
663 return 0
664 result = sorted(result, key=lambda k:k.get(key, '').split('|'),
665 cmp=lambda x,y : cmp(utif.try_int(x),utif.try_int(y)))
666
667 if sdnsh.description: # description debugging
668 print "get_model_from_url: result ", obj_type, url, len(result)
669
670 return result
671
672
673def validate_switch():
674 """
675 If /rest/v1/switches is cached, perform some validations on it.
676
677 -- verify that the announced interfaces names are case insensitive
678 -- verify the names only appear once
679 """
680
681 def duplicate_port(entry, name):
682 dpid = entry['dpid']
683
684 print 'Warning: switch %s duplicate interface names: %s' % (dpid, name)
685 if sdnsh.debug_backtrace:
686 for port in entry['ports']:
687 if port['name'] == name:
688 print 'SWTICH %s:%s PORT %s' % (entry, name, port)
689
690 def not_case_sensitive(entry, name):
691 dpid = entry['dpid']
692
693 ports = {}
694 for port in entry['ports']:
695 if port['name'].lower() == name:
696 ports[port['name']] = port
697
698 print 'Warning: switch %s case insentive interface names: %s' % \
699 (dpid, ' - '.join(ports.keys()))
700 if sdnsh.debug_backtrace:
701 for port in ports:
702 print 'SWTICH %s PORT %s' % (dpid, port)
703
704 url = "http://%s/rest/v1/switches" % sdnsh.controller
705 entries = url_cache.get_cached_url(url)
706 if entries:
707 for entry in entries:
708 dpid = entry['dpid']
709
710 # verify that the port names are unique even when case
711 # sensitive
712 all_names = [p['name'] for p in entry['ports']]
713 one_case_names = utif.unique_list_from_list([x.lower() for x in all_names])
714 if len(all_names) != len(one_case_names):
715 # Something is rotten, find out what.
716 for (i, port_name) in enumerate(all_names):
717 # use enumerate to drive upper-triangle comparison
718 for other_name in all_names[i+1:]:
719 if port_name == other_name:
720 duplicate_port(entry, port_name)
721 elif port_name.lower() == other_name.lower():
722 not_case_sensitive(entry, port_name)
723
724