Adding ONOS Segment Routing CLI files to new repo
diff --git a/cli/c_completions.py b/cli/c_completions.py
new file mode 100755
index 0000000..ac66a79
--- /dev/null
+++ b/cli/c_completions.py
@@ -0,0 +1,752 @@
+#
+# Copyright (c) 2011,2012,2013 Big Switch Networks, Inc.
+#
+# Licensed under the Eclipse Public License, Version 1.0 (the
+# "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# permissions and limitations under the License.
+#
+
+import os
+import re
+import modi
+import error
+import command
+import collections
+import utif
+
+from midw import *
+
+def check_rest_result(result, message=None):
+ if isinstance(result, collections.Mapping):
+ error_type = result.get('error_type')
+ if error_type:
+ raise error.CommandRestError(result, message)
+
+
+def pretty(text):
+ """
+ For object-type's, remove dashes, capitalize first character
+ """
+ return text.replace('-', ' ').capitalize()
+
+
+#
+# COMPLETION PROCS
+#
+# 'completions' is a dictionary, where the keys are the actual text
+# of the completion, while the value is the reason why this text
+# was added. The 'reason' provides the text for the two-column
+# help printed for the '?' character.
+#
+
+def collect_object_fields(obj_type, field, data, mode, completions,
+ prefix = None, other = None,
+ parent_field = None, parent_id = None, scoped = None):
+ """
+ Returns the list of possible completions for a particular obj-type.
+ """
+
+ data = dict(data)
+ if parent_field:
+ data[parent_field] = parent_id
+ if prefix:
+ data[field + '__startswith'] = prefix
+
+ key = mi.pk(obj_type)
+ if scoped:
+ obj_id = sdnsh.get_current_mode_obj()
+ if sdnsh.current_mode() != mode:
+ # XXX needs to be covered, shouldn't reach in like this
+ for x in sdnsh.mode_stack:
+ if x['mode_name'] == mode:
+ obj_id = x['obj']
+ obj_d = { key : obj_id }
+
+ if obj_type in mi.alias_obj_types:
+ # the submode ought to identify the foreign key
+ data[mi.alias_obj_type_field(obj_type)] = obj_id
+ else:
+ mi.split_compound_into_dict(obj_type, key, obj_d, is_prefix = True)
+ for (k,v) in obj_d.items():
+ if k != key and not k in data:
+ data[k] = v
+
+
+ # if this is one of the obj_type's associated with aliases, should
+ # the list of values be back-transformed into alias names?
+ # yes, because if the current value has an inverse alias, the existing
+ # inverse for the type implies that during a previous insert of this
+ # value, it was converted from its alias name to the current name.
+ #
+ # collect the complete collection of aliases, since its likely
+ # more than one back-to-alias conversion will be required, and query
+ # its value before obj_type in the hope that it was recently cached.
+ #
+ alias_obj_type = mi.obj_type_related_config_obj_type(obj_type)
+ if other and other in mi.alias_obj_type_xref:
+ alias_obj_type = mi.alias_obj_type_xref[other][0]
+ elif field != mi.pk(obj_type):
+ if mi.is_foreign_key(obj_type, field):
+ (alias_obj_type, fk_name) = mi.foreign_key_references(obj_type, field)
+ alias_obj_type = mi.obj_type_related_config_obj_type(alias_obj_type)
+ if alias_obj_type in mi.alias_obj_type_xref:
+ alias_obj_type = mi.alias_obj_type_xref[alias_obj_type][0]
+ else:
+ alias_obj_type = None
+ else:
+ if sdnsh.description: # description debugging
+ print 'collect_object_fields: no alias for %s ' \
+ 'field %s not pk, and not fk' % (obj_type, field)
+ alias_obj_type = None
+ elif obj_type in mi.alias_obj_type_xref:
+ alias_obj_type = mi.alias_obj_type_xref[obj_type][0]
+ else:
+ alias_obj_type = None
+
+ alias_dict = {}
+ if alias_obj_type:
+ foreign_field = mi.alias_obj_type_field(alias_obj_type)
+ alias_dict = create_obj_type_dict(alias_obj_type, foreign_field)
+ alias_key = mi.pk(alias_obj_type)
+
+ # Remove any data fields which have values of None, these are fields
+ # which are getting reset.
+ for reset_fields in [x for x in data.keys() if data[x] == None]:
+ del data[reset_fields]
+
+ # collect complete obj_type
+ if not mi.obj_type_has_model(obj_type):
+ result = rest_to_model.get_model_from_url(obj_type, data)
+ else:
+ result = sdnsh.rest_query_objects(obj_type, data)
+ check_rest_result(result)
+ if sdnsh.description: # description debugging
+ print "collect_object_fields:", obj_type, field, data, result
+
+ is_compound = mi.is_compound_key(obj_type, key)
+ d = {}
+ for item in result:
+ if is_compound:
+ mi.split_compound_into_dict(obj_type, key, item)
+ value = item.get(field)
+ # XXX hack to correctly format tag completions
+ if obj_type == 'tag' and field == 'id':
+ value = '%s.%s=%s' % tuple(value.split('|'))
+ # remember to only add new items
+ if value:
+ if type(value) == list:
+ # Need a mechanism to select values from the list, field's not enough
+ for item in value:
+ if utif.quote_string(str(item)) not in completions:
+ if str(item) in alias_dict:
+ alias_item = alias_dict[str(item)][0][alias_key]
+ if alias_item.startswith(prefix):
+ item = alias_item
+ d[utif.quote_string(str(item))] = None
+ elif utif.quote_string(str(value)) not in completions:
+ if str(value) in alias_dict:
+ alias_value = alias_dict[str(value)][0][alias_key]
+ if alias_value.startswith(prefix):
+ value = alias_value
+ d[utif.quote_string(str(value))] = None
+
+ # if there's an alias for this object, and a prefix is included,
+ # then the alias'es which match also need to be directly included,
+ # since its not clear whether the prefix applies to the actual
+ # id or the alias. since alias_dict is already the complete
+ # collection of aliases for this obj-type, use it for matching names
+ if alias_obj_type and prefix and prefix != '':
+ alias_pk = mi.pk(alias_obj_type)
+ for (n,v) in alias_dict.items():
+ # 'n' here is the foreign key reference to this obj-type
+ for item in [x[alias_pk] for x in v if x[alias_pk].startswith(prefix)]:
+ if utif.quote_string(str(item)) not in completions:
+ d[utif.quote_string(str(item))] = None
+
+ return utif.add_delim(list(d), ' ')
+
+
+def complete_object_field(obj_type, field, data, completions,
+ mode = None,
+ prefix = None, other = None, parent_field = None, parent_id = None, scoped = None):
+ """
+ Populate 'completions' with the values of the primary key for
+ the particular obj_type
+ """
+ if sdnsh.description: # description debugging
+ print "complete_object_field: ", obj_type, mode, field, data, scoped, other
+
+ if not mi.obj_type_exists(obj_type):
+ raise error.CommandDescriptionError("Unknown obj-type: %s" % obj_type)
+ result = collect_object_fields(obj_type, field, data, mode, completions,
+ prefix, other, parent_field, parent_id, scoped)
+ completions.update(dict([[x, "%s selection" % pretty(obj_type)]
+ for x in result]))
+
+
+def complete_tag_mapping(obj_type, field, data, completions,
+ prefix = None, other = None, mode = None,
+ parent_field = None, parent_id = None, scoped = None):
+ """
+ Translate the completion results from complete_object_field into
+ tag values of syntax <namespace.name>=<value
+ """
+ if not mi.obj_type_exists(obj_type):
+ raise error.CommandDescriptionError("Unknown obj-type: %s" % obj_type)
+
+ # since the prefix can contrict the search, and its not clear
+ # what the prefix applies to, collect all the possible values,
+ # compute wht the item would look like then match the prefix.
+ collection = collect_object_fields(obj_type, field, data, mode, completions,
+ '', other, parent_field, parent_id, scoped)
+ if prefix != "":
+ collection = [x for x in collection if x.startswith(prefix)]
+ completions.update(dict([[x, "tag selection"] for x in collection]))
+
+
+def complete_from_another(other, obj_type, field, data, completions, no_command,
+ prefix = None,
+ parent_field = None, parent_id = None, scoped = None,explicit=None):
+ """
+ Completion function used when another obj_type is used to populate
+ values for the current obj_type
+
+ the 'other' field identifies the obj_type to use to collect choices from,
+ it can consist of two parts other|field. When field isn't described here,
+ it comes from the description parameter, however, the 'field' value there may
+ be in use to describe the value of the associated action.
+
+ """
+ if sdnsh.description: # description debugging
+ print "complete_from_another:", other, field, data, parent_field, parent_id, scoped
+
+ # complete_from_another is intended to include other fields, which
+ # shouldn't apply for a no command.
+ if no_command:
+ return
+
+ if other.find('|') >= 0:
+ parts = other.split('|')
+ other = parts[0]
+ field = parts[1]
+
+ if not mi.obj_type_exists(other):
+ raise error.CommandDescriptionError("Unknown obj-type/other: %s" % other)
+
+ id = mi.pk(other)
+ data = dict(data)
+ if parent_field and parent_id:
+ data[parent_field] = parent_id
+ if prefix:
+ data[field + '__startswith'] = prefix
+ key = mi.pk(other)
+ if scoped:
+ key = mi.pk(other)
+ if type(scoped) == str and scoped in data:
+ obj_d = { key : data[scoped] }
+ else:
+ obj_d = { key : sdnsh.get_current_mode_obj() }
+ mi.split_compound_into_dict(other, key, obj_d, is_prefix = True)
+ for (k,v) in obj_d.items():
+ if k != key and not k in data:
+ data[k] = v
+ if mi.is_primitive_compound_key(other, key):
+ # try to use the field values to populate the primary key...
+ value = ""
+ s = mi.compound_key_separator(other, key)
+ missing = None
+ for kf in mi.deep_compound_key_fields(other, key):
+ if kf in data:
+ value += data[kf] + s
+ else:
+ # the fields must appear in order
+ missing = kf
+ break
+ # For prefix extention to work here, the other field must have
+ # named the field, for example switch's interface completion,
+ # uses "other : 'port|number'"
+ post_prefix_match = False
+ if prefix:
+ post_prefix_match = True
+ if missing == field:
+ value += prefix
+ post_prefix_match = False
+ if mi.obj_type_has_model(other):
+ result = sdnsh.get_table_from_store(other, key, value)
+ else:
+ result = rest_to_model.get_model_from_url(other, { key : value } )
+
+ if post_prefix_match:
+ # try to match the missing field, more work ought to be done
+ # to identify whether the 'missing' field is the correect to match against
+ #
+ result = [x for x in result
+ if field in x and str(x[field]).startswith(prefix)]
+ elif mi.is_compound_key(other, key):
+ search = {}
+ if parent_id:
+ from_id = {mi.pk(obj_type) : parent_id}
+ mi.split_compound_into_dict(obj_type,
+ mi.pk(obj_type),
+ from_id,
+ is_prefix = True)
+ # the field name used to collapse the result is the last
+ # field in the compound key (id of 'other'), this may need
+ # improvement for other commands
+ for deep_field in mi.deep_compound_key_fields(other, key):
+ if deep_field in from_id:
+ search[deep_field] = from_id[deep_field]
+ if deep_field in data:
+ search[deep_field] = data[deep_field]
+ if scoped:
+ # move known compound fields from obj_d into search.
+ for deep_field in mi.deep_compound_key_fields(other, key):
+ if deep_field in obj_d:
+ search[deep_field] = obj_d[deep_field]
+ #
+ # possibly other search keys?
+ if prefix:
+ search[field + '__startswith'] = prefix
+ if explicit:
+ search.clear()
+ search[scoped]=data[scoped]
+ if prefix:
+ search[field + '__startswith'] = prefix
+ if mi.obj_type_has_model(other):
+ result = sdnsh.rest_query_objects(other, search)
+ else:
+ result = rest_to_model.get_model_from_url(other, search )
+ elif mi.obj_type_has_field(other, field) and mi.is_primary_key(other, field):
+ result = utif.add_delim(objects_starting_with(other, prefix), ' ')
+ completions.update(dict([[x, "%s selection" % pretty(other)]
+ for x in result]))
+ return
+ elif mi.obj_type_has_field(obj_type, field) and \
+ mi.is_foreign_key(obj_type, field):
+ # look up the values of the foreign key's from the other table
+ (fk_obj_type, fk_fn) = mi.foreign_key_references(obj_type, field)
+ result = sdnsh.get_table_from_store(fk_obj_type, fk_fn, prefix)
+ field = fk_fn
+ elif mi.obj_type_has_field(obj_type, field) and field == other:
+ # In this situation, this obj_type has a field, which seems to be named
+ # based on the other model's name, which seems to be requesting to
+ # search the other model.
+ field = mi.pk(other)
+ result += utif.add_delim(objects_starting_with(other, prefix), ' ')
+ completions.update(dict([[x, "%s selection" % pretty(other)]
+ for x in result]))
+ return
+ else:
+ if mi.obj_type_has_model(other):
+ result = sdnsh.rest_query_objects(other, data)
+ else:
+ result = rest_to_model.get_model_from_url(other, data)
+
+ check_rest_result(result)
+ if sdnsh.description: # description debugging
+ print "complete_from_another:", other, field, data, len(result)
+
+ d = {}
+ for item in result:
+ value = item.get(field)
+ # XXX hack to correctly format tag completions
+ if other == 'tag':
+ value = '%s.%s=%s' % tuple(value.split('|'))
+ # assume that 'values' are 'unique' within results
+ if value and utif.quote_string(value) not in completions:
+ d[utif.quote_string(str(value))] = None
+
+ if sdnsh.description: # description debugging
+ print "complete_from_another: final", other, field, data, d.keys()
+
+ result = utif.add_delim(list(d), ' ')
+ completions.update(dict([[x, "%s selection" % pretty(other)]
+ for x in result]))
+
+
+def complete_alias_choice(obj_type, field, data, prefix, completions, no_command,
+ other = None, scoped = None):
+ """
+ Complete selections from an external object (unlreated to this
+ object stack's details), only returning unique keys, either
+ aliases for the obj_type, or primary keys.
+
+ This ought to be improved, objects_starting_with() in
+ the cli.py, is primarily intended to be use within cli.py
+ """
+ if not mi.obj_type_exists(obj_type):
+ raise error.CommandDescriptionError("Unknown obj-type: %s" % obj_type)
+
+ if sdnsh.description: # description debugging
+ print "complete_alias_choice:", obj_type, field, other, data, prefix, scoped
+
+ if other and no_command == False:
+ parts = other.split('|')
+ obj_type = parts[0]
+ if len(parts) > 1:
+ # what to do with more parts?
+ field = parts[1]
+
+ if not mi.obj_type_has_field(obj_type, field):
+ raise error.CommandDescriptionError("Unknown field %s for obj-type: %s"
+ % (field, obj_type))
+
+
+ # quote string? alias choices ought to never have special characters
+ result = utif.add_delim(objects_starting_with(obj_type, prefix, field), ' ')
+ completions.update(dict([[x, "%s alias selection" % pretty(obj_type)]
+ for x in result]))
+
+
+def complete_config(prefix, data, completions, copy = False):
+ """
+ Complete selections for the 'copy' command.
+ """
+
+ configs = sdnsh.store.get_user_data_table('', "latest")
+
+ # exclude source if its in the data
+ source = data.get('source','')
+ src_dst = 'source' if source == '' else 'destination'
+
+ any = False
+ any_config = False
+
+ if copy:
+ if 'running-config'.startswith(prefix):
+ if source != 'running-config':
+ completions['running-config '] = 'running-config %s' % src_dst
+
+ for c in configs:
+ if ('config://' + c['name']).startswith(prefix):
+ if source != "config://" + c['name']:
+ completions["config://" + c['name'] + ' '] = \
+ 'Saved Configuration %s' % src_dst
+ any_config = True
+
+ if source != '' and 'config://'.startswith(prefix):
+ completions['config://'] = 'config prefix %s' % src_dst
+
+ if copy:
+ for additions in ["http://", "file://", "ftp://", "tftp://", 'config://' ]:
+ if additions.startswith(prefix):
+ completions[additions] = 'other %s' % src_dst
+
+
+def complete_interface_list(prefix, data, completions):
+ """
+ Interface lists are comma separated interfaces or range
+ of interfaces.
+
+ The prefix here plays an important role in determining what
+ ought to appear nest.
+ """
+ if not 'switch' in data:
+ return
+
+ def switch_interfaces_startingwith(interfaces, intf, prefix, completions):
+ result = [prefix + x for x in interfaces.keys() if x.startswith(intf)]
+ completions.update(dict([[x, "known interface"] for x in result]))
+ return
+
+ def higher_interfaces(interfaces, intf, prefix, completions):
+ # depend on having an integer as the last component
+ last_digits = re.compile(r'(.*)(\d+)$')
+ match = last_digits.search(intf)
+ if match:
+ if_name = match.group(1)
+ first = int(match.group(2))
+ for i in interfaces:
+ match = last_digits.search(i)
+ if match and match.group(1) == if_name and int(match.group(2)) > first:
+ completions[prefix + match.group(2)] = 'inteface choice.'
+
+
+ ports = rest_to_model.get_model_from_url('interfaces', data)
+ interfaces = dict([[x['name'], x] for x in ports])
+ sic = sdnsh.get_table_from_store('switch-interface-config',
+ 'switch', data['switch'])
+ interfaces.update(dict([[x['name'], x] for x in sic]))
+
+ # peek at the last character in the prefix:
+ # if it's a dash, then choose interfaces with the same prefix,
+ # if its a comma, then chose another interface
+
+ front_item = ''
+ if len(prefix) > 0:
+ if prefix[-1] == '-':
+ # complete more choices
+ previous = prefix[:-1]
+ if len(previous):
+ last_item = previous.split(',')[-1]
+ if last_item in interfaces:
+ higher_interfaces(interfaces, last_item, prefix, completions)
+ return
+
+ if prefix[-1] != ',':
+ if len(prefix) > 2:
+ parts = prefix.split(',')
+ last_item = parts[-1]
+ # see if the last_item of prefix is a known interface.
+ if last_item in interfaces:
+ completions[prefix + ','] = 'List of interfaces'
+ completions[prefix + '-'] = 'Range of interfaces'
+ completions[prefix + ' <cr>'] = 'Current interfaces selection'
+ return
+ # see if the last item is a range (intf in front, then a dash)
+ c = [y for y in [x for x in interfaces if last_item.startswith(x)]
+ if len(last_item) > len(y) and last_item[len(y)] == '-']
+ if len(c):
+ # found interface with a dash afterwards
+ # could actually check that everything after '-' is digits
+ completions[prefix + ','] = 'List of interfaces'
+ completions[prefix + ' <cr>'] = 'Current interfaces selection'
+ return
+
+ first_items = ''.join(['%s,' % x for x in parts[:-1]])
+ switch_interfaces_startingwith(interfaces,
+ last_item,
+ first_items,
+ completions)
+ return
+
+ # single token prefix
+ switch_interfaces_startingwith(interfaces, prefix, '', completions)
+ return
+ # last character is a comma
+ if len(prefix) == 1:
+ return # just a comma
+
+ # crack into parts, see if the last is a range, if so, then
+ # the choices are a comma or a <cr>
+ parts = prefix.split(',')
+ front_item = ','.join(parts[:-1]) + ','
+ prefix = parts[-1]
+ # fall through
+
+ switch_interfaces_startingwith(interfaces, prefix, front_item, completions)
+ return
+
+
+def complete_staticflow_actions(prefix, data, completions):
+ # peek at the last character in the prefix:
+ # if it's a comma, then choose all the possible actions
+ # if its a equal, then display the choices for this option
+
+ prefix_parts = []
+
+ actions = {
+ 'output=' : 'Describe packet forwarding',
+ 'enqueue=' : 'Enqueue packet',
+ 'strip-vlan=' : 'Strip Vlan',
+ 'set-vlan-id=' : 'Set Vlan',
+ 'set-vlan-priority=' : 'Set Priority',
+ 'set-src-mac=' : 'Set Src Mac',
+ 'set-dst-mac=' : 'Set Dst Mac',
+ 'set-tos-bits=' : 'Set TOS Bits',
+ 'set-src-ip=' : 'Set IP Src',
+ 'set-dst-ip=' : 'Set IP Dst',
+ 'set-src-port=' : 'Set Src IP Port',
+ 'set-dst-port=' : 'Set dst IP Port',
+ }
+
+ action_choices = {
+ ('output=', 'all') : 'Forward to all ports',
+ ('output=', 'controller') : 'Forward to controller',
+ ('output=', 'local') : 'Forward to local',
+ ('output=', 'ingress-port') : 'Forward to ingress port',
+ ('output=', 'normal') : 'Forward to ingress port',
+ ('output=', 'flood') : 'Forward, flood ports',
+ ('output=', ('<number>', '<number>')) : 'Forward, to a specific port',
+
+ ('enqueue=', ('<portNumber>.<queueID>', '<portNumber>.<queueID>')) : 'Enqueue to port, queue id',
+
+ ('set-vlan-id=',('<vlan number>','<vlan number>')) : 'Set vlan to <vlan number>',
+
+ ('set-vlan-priority=',('<vlan prio>','<vlan prio>')) : 'Set vlan priority to <prio>',
+
+ ('set-tos-bits=',('<number>',)) : 'Set TOS bits',
+ ('set-src-mac=',('<src-mac-address>',)) : 'Set src mac address',
+
+ ('set-dst-mac=',('<dst-mac-address>',)) : 'Set dst mac address',
+
+ ('set-src-ip=',('<src-ip-address>',)) : 'Set src mac address',
+
+ ('set-dst-ip=',('<src-ip-address>',)) : 'Set dst ip address',
+ }
+
+ for ps in prefix.split(','):
+ ps_parts = ps.split('=')
+ if len(ps_parts) == 1 and ps_parts[0] != '':
+ # possibly incomplete item before the '='
+ for choice in [x for x in actions.keys() if x.startswith(ps_parts[0])]:
+ completions[choice] = actions[choice]
+ return
+ elif len(ps_parts) == 2:
+ if len(ps_parts[0]) and len(ps_parts[1]):
+ prefix_parts.append((ps_parts[0], ps_parts[1]))
+ elif len(ps_parts[0]) and len(ps_parts[1]) == 0:
+ prefix_parts.append((ps_parts[0], ))
+
+ if prefix == '' or prefix.endswith(','):
+ completions.update(actions)
+ elif prefix.endswith('='):
+ last = prefix_parts[-1]
+ for ((match, next), desc) in action_choices.items():
+ if match[:-1] != last[0]:
+ continue
+ if type(next) == str:
+ completions[match + next] = desc
+ elif type(next) == tuple:
+ completions[(match + next[0], match + next[0])] = desc
+ # else? display error?
+ elif len(prefix_parts):
+ last = prefix_parts[-1]
+ if len(last) == 1:
+ pass
+ elif len(last) == 2:
+ # try to find the left item
+ for ((match, next), desc) in action_choices.items():
+ if match[:-1] != last[0]:
+ continue
+ if type(next) == str and next == last[1]:
+ eol = prefix + ' <cr>'
+ completions[(eol, eol)] = 'Complete Choice'
+ another = prefix + ','
+ completions[(another, another)] = 'Add another action'
+ elif type(next) == str and next.startswith(last[1]):
+ base_part = ''.join(prefix.rpartition(',')[:-1])
+ completions[base_part + last[0] + '=' + next] = 'Complete selection'
+ elif len(last[1]):
+ # hard to say what choices can be added here,
+ # there are some characters after '=', but none
+ # which match some prefix.
+ pass
+
+ # how to match the values?
+
+
+def complete_description_versions(prefix, completions):
+ for element in os.listdir(sdnsh.command_packages_path()):
+ if element == '__init__.py':
+ pass
+ elif element.startswith('version'):
+ # len('element') -> 7
+ version = "%2.2f" % (float(element[7:]) / 100)
+ if version[-2:] == '00':
+ version = version[:2] + '0'
+ if version.startswith(prefix):
+ completions[version] = 'VERSION'
+ if version == '2.0': # currently if 2.0 exists, so does 1.0
+ if '1.0'.startswith(prefix):
+ completions['1.0'] = 'VERSION'
+ else:
+ if element.startswith(prefix):
+ completions[element] = 'VERSION'
+
+
+def complete_log_names(prefix, data, completions):
+ """
+ Enumerate all the log file choices based on replies from the REST API.
+ """
+ controller = data.get('controller')
+ for ip_port in controller_ip_and_port(controller):
+ url = log_url(ip_and_port = ip_port)
+ log_names = command.sdnsh.rest_simple_request_to_dict(url)
+ for log in log_names:
+ log_name = log['log']
+ if log_name.startswith(prefix):
+ completions[log_name + ' '] = 'Log Selection'
+
+
+
+def init_completions(bs, modi):
+ global sdnsh, mi
+ sdnsh = bs
+ mi = modi
+
+ command.add_completion('complete-object-field', complete_object_field,
+ {'kwargs': {'obj_type' : '$obj-type',
+ 'parent_field' : '$parent-field',
+ 'parent_id' : '$current-mode-obj-id',
+ 'field' : '$field',
+ 'prefix' : '$text',
+ 'data' : '$data',
+ 'scoped' : '$scoped',
+ 'other' : '$other',
+ 'mode' : '$mode',
+ 'completions' : '$completions'}})
+
+ command.add_completion('complete-tag-mapping', complete_tag_mapping,
+ {'kwargs': {'obj_type' : '$obj-type',
+ 'parent_field' : '$parent-field',
+ 'parent_id' : '$current-mode-obj-id',
+ 'field' : '$field',
+ 'prefix' : '$text',
+ 'data' : '$data',
+ 'scoped' : '$scoped',
+ 'other' : '$other',
+ 'mode' : '$mode',
+ 'completions' : '$completions'}})
+
+ command.add_completion('complete-from-another', complete_from_another,
+ {'kwargs': {'other' : '$other',
+ 'obj_type' : '$obj-type',
+ 'parent_field' : '$parent-field',
+ 'parent_id' : '$current-mode-obj-id',
+ 'field' : '$field',
+ 'prefix' : '$text',
+ 'data' : '$data',
+ 'scoped' : '$scoped',
+ 'completions' : '$completions',
+ 'no_command' : '$is-no-command',
+ 'explicit' : '$explicit', }})
+
+ command.add_completion('complete-alias-choice', complete_alias_choice,
+ {'kwargs': {'obj_type' : '$obj-type',
+ 'field' : '$field',
+ 'other' : '$other',
+ 'prefix' : '$text',
+ 'data' : '$data',
+ 'scoped' : '$scoped',
+ 'completions' : '$completions',
+ 'no_command' : '$is-no-command', }})
+
+ command.add_completion('complete-config', complete_config,
+ {'kwargs': {'prefix': '$text',
+ 'data': '$data',
+ 'completions': '$completions'}})
+
+ command.add_completion('complete-config-copy', complete_config,
+ {'kwargs': {'prefix': '$text',
+ 'data': '$data',
+ 'completions': '$completions',
+ 'copy' : True }})
+
+ command.add_completion('complete-interface-list', complete_interface_list,
+ {'kwargs': {'prefix': '$text',
+ 'data': '$data',
+ 'completions': '$completions'}})
+
+ command.add_completion('complete-staticflow-actions', complete_staticflow_actions,
+ {'kwargs': {'prefix': '$text',
+ 'data': '$data',
+ 'completions': '$completions'}})
+
+ command.add_completion('description-versions', complete_description_versions,
+ {'kwargs': {'prefix': '$text',
+ 'completions': '$completions'}})
+
+ command.add_completion('complete-log-names', complete_log_names,
+ {'kwargs': {'prefix' : '$text',
+ 'data' : '$data',
+ 'completions': '$completions'}})
+