def validate_switch(): """ If /rest/v1/switches is cached, perform some validations on it. -- verify that the announced interfaces names are case insensitive -- verify the names only appear once """ def duplicate_port(entry, name): dpid = entry['dpid'] print 'Warning: switch %s duplicate interface names: %s' % (dpid, name) if sdnsh.debug_backtrace: for port in entry['ports']: if port['name'] == name: print 'SWTICH %s:%s PORT %s' % (entry, name, port) def not_case_sensitive(entry, name): dpid = entry['dpid'] ports = {} for port in entry['ports']: if port['name'].lower() == name: ports[port['name']] = port print 'Warning: switch %s case insentive interface names: %s' % \ (dpid, ' - '.join(ports.keys())) if sdnsh.debug_backtrace: for port in ports: print 'SWTICH %s PORT %s' % (dpid, port) url = "http://%s/rest/v1/switches" % sdnsh.controller entries = url_cache.get_cached_url(url) if entries: for entry in entries: dpid = entry['dpid'] # verify that the port names are unique even when case # sensitive all_names = [p['name'] for p in entry['ports']] one_case_names = utif.unique_list_from_list([x.lower() for x in all_names]) if len(all_names) != len(one_case_names): # Something is rotten, find out what. for (i, port_name) in enumerate(all_names): # use enumerate to drive upper-triangle comparison for other_name in all_names[i+1:]: if port_name == other_name: duplicate_port(entry, port_name) elif port_name.lower() == other_name.lower(): not_case_sensitive(entry, port_name)
def interface_ranges(names): """ Given a list of interfaces (strings), in any order, with a numeric suffix, collect together the prefix components, and create ranges with adjacent numeric interfaces, so that a large collection of names becomes easier to read. At the worst, the list will be as complicated as the original (which would typically be very unlikely) Example: names <- ['Eth0', 'Eth1', 'Eth2', 'Eth4', 'Eth5', 'Eth8'] result <- ['Eth0-2', 'Eth4-5', 'Eth8'] names <- ['1','2','3'] result <- ['1-3'] """ # collect the interfaces into dictionaries based on prefixes # ahead of groups of digits. groups = {} def is_digit(c): c_ord = ord(c) if c_ord >= ord('0') and c_ord <= ord('9'): return True return False for name in names: if is_digit(name[-1]): for index in range(-2, -len(name) - 1, -1): if not is_digit(name[index]): index += 1 break else: index = -len(name) prefix = name[:index] number = int(name[index:]) if not prefix in groups: groups[prefix] = [] groups[prefix].append(number) else: groups[name] = [] for prefix in groups: groups[prefix] = sorted(utif.unique_list_from_list(groups[prefix])) ranges = [] for (prefix, value) in groups.items(): if len(value) == 0: ranges.append(prefix) else: low = value[0] prev = low for next in value[1:] + [value[-1] + 2]: # +[] flushes last item if next > prev + 1: if prev == low: ranges.append('%s%s' % (prefix, low)) else: ranges.append('%s%s-%s' % (prefix, low, prev)) low = next prev = next return ranges
def format_table(self, data_list, display_format = None, field_ordering="default"): """ Takes in list of dicts and generates nice table, e.g. id slice_id MAC Address ip Switch ID ------------------------------------------------ 1 1 00:00:00:00:01:03 10013 150861407404 2 2 00:00:00:00:01:01 10011 150861407404 3 1 00:00:00:00:02:03 10023 150866955514 @param data_list - a list of dicts @param format describes the format of the output table to display @param field_ordering is the field_ordering identifier in the model, there can be multiple ("default", "brief", "detailed") """ # # first, determine a list of fields to be printed, then using that list, # determine the fields width of each field, including calling any formatting # function, then format the result # # during the format computation, replace the value with the 'formatted value' # to prevent multiple calls to the same formatting funcition # if not data_list or not type(data_list) == list: if type(data_list) == dict and "error_type" in data_list: return data_list.get("description", "Internal error") return "None." format_info = self.table_info.get(display_format, None) if self.sdnsh.description: if format_info == None: print 'format_table: missing format %s' % display_format else: format_from = format_info.get('self', '') print 'format_table: %s %s %d entries' % ( display_format, format_from, len(data_list)) field_widths = {} field_headers = {} fields_to_print = [] # # do the 'figur'n for which fields will get printed. # # to determine the length, call the formatting function, and replace the # value for that field with the updated value; then 'cypher the length. # # note that field_widths.keys() are all the possible fields # check if the headers makes any field wider and set fields_to_print # if format_info: if 'field-orderings' in format_info: fields_to_print = format_info['field-orderings'].get(field_ordering, []) if len(fields_to_print) == 0: # either no field_orderings or couldn't find specific fields_to_print = format_info['fields'].keys() for f in fields_to_print: header = self.get_header_for_field(format_info, f) field_headers[f] = header field_widths[f] = max(len(header), field_widths.get(f, 0)) # LOOK! not done now... add in extra fields discovered in data_list if desired # right now, fields_to_print is a projection on the data else: # get fields_to_print from the field names in data_list, # which is (intended to be) a list of dictionaries all_fields = utif.unique_list_from_list(sum([x.keys() for x in data_list], [])) fields_to_print = sorted(all_fields) if self.sdnsh.description: print 'format_table: field order "%s" fields %s' % \ (field_ordering, fields_to_print) # # generate a fields_to_print ordered list with field_widths for each # by going through all data and then using field_ordering if avail. # row_index = 0 for row in data_list: row_index += 1 if not 'Idx' in row: row['Idx'] = row_index for key in fields_to_print: #for (k,v) in row.items(): if format_info: # don't worry about header here - do that soon below info = self.get_field_info(format_info, key) if info and info.get('formatter'): row[key] = str(info['formatter'](row.get(key, ''), row)) w = len(row[key]) else: w = len(str(row.get(key, ''))) else: field_headers[key] = self.format_as_header(key) w = max(len(str(row[key])), len(field_headers[key])) field_widths[key] = max(w, field_widths.get(key, 0)) # # generate the format_str and header lines based on fields_to_print # format_str_per_field = [] for f in fields_to_print: format_str_per_field.append("%%(%s)-%ds" % (f, field_widths[f])) row_format_str = " ".join(format_str_per_field) + "\n" # # finally print! only caveat is to handle sparse data with a blank_dict # let result be a list, and append new strings to generate the final result, # (for better python performance) # result= [] result.append(" ".join(format_str_per_field) % field_headers + "\n") result.append("|".join(["-"*field_widths[f] for f in fields_to_print]) + "\n") # I <3 python too blank_dict = dict([(f,"") for f in fields_to_print]) for row in data_list: result.append(row_format_str % dict(blank_dict, **row)) return ''.join(result)
def interface_ranges(names): """ Given a list of interfaces (strings), in any order, with a numeric suffix, collect together the prefix components, and create ranges with adjacent numeric interfaces, so that a large collection of names becomes easier to read. At the worst, the list will be as complicated as the original (which would typically be very unlikely) Example: names <- ['Eth0', 'Eth1', 'Eth2', 'Eth4', 'Eth5', 'Eth8'] result <- ['Eth0-2', 'Eth4-5', 'Eth8'] names <- ['1','2','3'] result <- ['1-3'] """ # collect the interfaces into dictionaries based on prefixes # ahead of groups of digits. groups = {} def is_digit(c): c_ord = ord(c) if c_ord >= ord('0') and c_ord <= ord('9'): return True return False for name in names: if is_digit(name[-1]): for index in range(-2, -len(name)-1, -1): if not is_digit(name[index]): index += 1 break; else: index = -len(name) prefix = name[:index] number = int(name[index:]) if not prefix in groups: groups[prefix] = [] groups[prefix].append(number) else: groups[name] = [] for prefix in groups: groups[prefix] = sorted(utif.unique_list_from_list(groups[prefix])) ranges = [] for (prefix, value) in groups.items(): if len(value) == 0: ranges.append(prefix) else: low = value[0] prev = low for next in value[1:] + [value[-1] + 2]: # +[] flushes last item if next > prev + 1: if prev == low: ranges.append('%s%s' % (prefix, low)) else: ranges.append('%s%s-%s' % (prefix, low, prev)) low = next prev = next return ranges