def init(self):

        self.vendordb = VendorDB()
        self.vendordb.init()

        parser = OptionParser()
        parser.add_option("-c",
                          "--controller",
                          dest="controller",
                          help="set default controller to CONTROLLER",
                          metavar="CONTROLLER",
                          default=self.controller)
        (options, args) = parser.parse_args()
        self.controller = options.controller
        if not self.controller:
            self.controller = "127.0.0.1:8000"

        if not sys.stdin.isatty():
            self.batch = True

        self.init_obj_type_info_dict()

        self.pp = PrettyPrinter(self.obj_type_info_dict)
        self.store = StoreClient()
        self.store.set_controller(self.controller)
    def init(self):
        
        self.vendordb = VendorDB()
        self.vendordb.init()
        
        parser = OptionParser()
        parser.add_option("-c", "--controller", dest="controller",
                          help="set default controller to CONTROLLER", 
                          metavar="CONTROLLER", default=self.controller)
        (options, args) = parser.parse_args()
        self.controller = options.controller
        if not self.controller:
            self.controller = "127.0.0.1:8000"

        if not sys.stdin.isatty():
            self.batch = True

        self.init_obj_type_info_dict()

        self.pp = PrettyPrinter(self.obj_type_info_dict)
        self.store = StoreClient()
        self.store.set_controller(self.controller)
class Validate():

    # initialize in init_obj_type_info
    obj_type_info_dict = {}         # see init_obj_type_info_dict
    obj_types = [] 
    obj_keys = {}
    
    known_controllers = ["127.0.0.1:8000"]
    controller = None
    # LOOK! manage this separately until we can for sure talk to eth0 addr instead of 127.0.0.1
    controller_for_prompt = "127.0.0.1:8000"
    cluster = "default"

    run = True

    # Cached options for last completion
    last_line = None
    last_options = None
    
    # Are we running in batch mode, i.e. "cat commands | cli.py"
    batch = False

    # used for parsing as an arg
    local_name_pattern = "localhost://([A-Za-z0-9_:@\-\.\/]+$)"

    # contained objects
    pp = None
    store = None
    model_handler = None

    #
    # --------------------------------------------------------------------------------
    # init_obj_type_info_dict
    #
    #  Builds the init_obj_type_info_dict, which is a dictionary indexed by
    #  the current mode, which also results in a dictionary, then indexed
    #  by a either a 'field' or 'field_ordering' key.
    #
    #  When init_obj_type_info_dict is indexed by the table/model name, the
    #  value is a dictionary.  That dictionary has several keys:
    #  - 'fields'
    #  - 'field_orderings'
    #
    #  The 'fields' indexed result returns a dictionary, each of which
    #  is indexed by the names of the fields within the table/model. further
    #  indicies describe details about that field within the table:
    #  - 'formatter' desscribes the prettyPrinter function for that field
    #  - 'primary_key' identifes this field as the key for the table/model.
    #  - 'verbose_name' identfies an additonal name for the field, inteneded
    #                   to be more descriptive
    #  - 'has_rest_model'  True/False
    #  - 'json_serialize_string'  True/False
    #  - 'help_text'  String providing more clues about the intent of this field
    #
    #  The 'field_ordering' dictionary associated with the name of the table/model
    #  is used to order the output.
    #
    #  Also populates the self.obj_keys[], which is a dictionary mapping the table/model
    #  name to the name of the storage key (table/model's column) for that table.
    #
    def init_obj_type_info_dict(self):
        self.cli_model_info = CliModelInfo()
        self.obj_type_info_dict = self.cli_model_info.get_complete_obj_type_info_dict()
        self.obj_types = [k for (k,v) in self.obj_type_info_dict.items()
                          if 'has_rest_model' in v]
        for (k,d) in self.obj_type_info_dict.items():
            candidate_keys = [f for f in d['fields'].keys() 
                              if d['fields'][f].get('primary_key', False)]
            if len(candidate_keys) > 0:
                self.obj_keys[k] = candidate_keys[0]


    #
    # --------------------------------------------------------------------------------
    # make_unit_formatter
    #
    def make_unit_formatter(self, units):
        return lambda x,y: '%s %s' % (x, units)

    #
    # --------------------------------------------------------------------------------
    # init_obj_type_info_dict
    #
    #  Builds the init_obj_type_info_dict, which is a dictionary indexed by
    #  the current mode, which also results in a dictionary, then indexed
    #  by a either a 'field' or 'field_ordering' key.
    #
    #  When init_obj_type_info_dict is indexed by the table/model name, the
    #  value is a dictionary.  That dictionary has several keys:
    #  - 'fields'
    #  - 'field_orderings'
    #
    #  The 'fields' indexed result returns a dictionary, each of which
    #  is indexed by the names of the fields within the table/model. further
    #  indicies describe details about that field within the table:
    #  - 'formatter' desscribes the prettyPrinter function for that field
    #  - 'primary_key' identifes this field as the key for the table/model.
    #  - 'verbose_name' identfies an additonal name for the field, inteneded
    #                   to be more descriptive
    #  - 'has_rest_model'  True/False
    #  - 'json_serialize_string'  True/False
    #  - 'help_text'  String providing more clues about the intent of this field
    #
    #  The 'field_ordering' dictionary associated with the name of the table/model
    #  is used to order the output.
    #
    #  Also populates the self.obj_keys[], which is a dictionary mapping the table/model
    #  name to the name of the storage key (table/model's column) for that table.
    #
    def init_obj_type_info_dict(self):
        self.cli_model_info = CliModelInfo()
        self.obj_type_info_dict = self.cli_model_info.get_complete_obj_type_info_dict()
        self.obj_types = [k for (k,v) in self.obj_type_info_dict.items()
                          if 'has_rest_model' in v]
        for (k,d) in self.obj_type_info_dict.items():
            candidate_keys = [f for f in d['fields'].keys() 
                              if d['fields'][f].get('primary_key', False)]
            if len(candidate_keys) > 0:
                self.obj_keys[k] = candidate_keys[0]

    #
    # --------------------------------------------------------------------------------
    # init
    #
    def init(self):
        
        self.vendordb = VendorDB()
        self.vendordb.init()
        
        parser = OptionParser()
        parser.add_option("-c", "--controller", dest="controller",
                          help="set default controller to CONTROLLER", 
                          metavar="CONTROLLER", default=self.controller)
        (options, args) = parser.parse_args()
        self.controller = options.controller
        if not self.controller:
            self.controller = "127.0.0.1:8000"

        if not sys.stdin.isatty():
            self.batch = True

        self.init_obj_type_info_dict()

        self.pp = PrettyPrinter(self.obj_type_info_dict)
        self.store = StoreClient()
        self.store.set_controller(self.controller)


    #
    # --------------------------------------------------------------------------------
    # parse_optional_parameters
    #
    def parse_optional_parameters(self, params, words):
        parsed = {}
        i = 0
        while i < len(words):
            word = words[i]
            possible = [x for x in params if x.startswith(word)]
            if len(possible) == 0:
                raise ParamException('unknown option: %s' % word)
            elif len(possible) > 1:
                raise ParamException('ambiguous option: %s\n%s' % 
                                     (word, "\n".join(possible)))
            else:
                param_name = possible[0]
                param = params[param_name]
                if (param['type'] == 'flag'):
                    parsed[param_name] = True
                else:
                    if i+1 < len(words):
                        argument = words[i+1]
                        if (param['type'] == 'string'):
                            parsed[param_name] = argument
                        elif (param['type'] == 'int'):
                            try:
                                parsed[param_name] = int(argument)
                            except ValueError:
                                raise ParamException('option %s requires ' + 
                                                     'integer argument'
                                                     % word)
                        elif (param['type'] == 'enum'):
                            arg_possible = [x 
                                            for x in param['values'] 
                                            if x.startswith(argument)]
                            if (len(arg_possible) == 0):
                                raise ParamException('option %s value must be in (%s)' % 
                                                     (word,", ".join(param['values'])))
                            elif (len(arg_possible) > 1):
                                raise ParamException('ambiguous option %s value:\n%s' % 
                                                     (word, "\n".join(arg_possible)))
                            else:
                                parsed[param_name] = arg_possible[0]
                        i += 1
                    else:
                        raise ParamException('option %s requires an argument' 
                                                 % word)
            i += 1
        return parsed

    #
    # --------------------------------------------------------------------------------
    # rest_error_to_dict
    #   Turn an exception into an error dictionary, which can later be printed.
    #   using rest_error_dict_to_message().  
    #
    def rest_error_to_dict(self, e, detail=None):
        errors = None
        # try to identifify validation requests
        if isinstance(e, httplib.BadStatusLine):
            errors = {'connection_error' : 'REST API server %s: '
                                           'server not running' %
                                           self.controller}
            return errors

        elif isinstance(e, urllib2.HTTPError):
            code = e.code
            error_returned = e.readline()

            if code == 404:
                if detail:
                    errors = {'not_found_error' : 'Not Found: %s' % detail}
                else:
                    errors = {'not_found_error' : 'Not Found: %s' % error_returned}
            elif code == 500 or code == 403:
                errors = {'connection_error' : 'REST API server %s unable to connect: '
                                               'Cassandra possibly not running' %
                                                self.controller}
            elif code == 400:
                try:
                    errors = json.loads(error_returned)
                except:
                    # if the error can't be converted into a dictionary, then imbed the complete
                    # errors as the value for a specific error key.
                    errors = {'error_result_error': "Can't convert returned error: %s" % error_returned}
                    pass
            else:
                errors = {'unknown_error': 'HttpError %s' % error_returned}
        else:
            errors = {'unknown_error': "Need error managmenet for error %s" % type(e)}

        return errors

    #
    # --------------------------------------------------------------------------------
    # rest_error_dict_to_message
    #   Turn an rest_error_dict returned from rest_error_to_dict
    #   into an error message which can ge printed.  Code assumes multiple errors
    #   won't occur; if a 'field_error' exists, for example, a 'model_error' won't
    #   also be posted in the error
    #
    def rest_error_dict_to_message(self, rest_error_dict):
        error_msg = ""
        if 'field_errors' in rest_error_dict:
            for (k,v) in rest_error_dict['field_errors'].items():
                error_msg += "Syntax error: field %s: %s" % (k,v)
            # traceback.print_stack(), to find out why the error occured
        elif 'model_error' in rest_error_dict:
            error_msg += "Error: %s" % rest_error_dict['model_error']
        elif 'not_found_error' in rest_error_dict:
            error_msg += "Error: %s" % rest_error_dict['not_found_error']
        elif 'connection_error' in rest_error_dict:
            error_msg += rest_error_dict['connection_error']
        elif 'error_result_error' in rest_error_dict:
            error_msg += rest_error_dict['error_result_error']
        elif 'unknown_error' in rest_error_dict:
            error_msg += rest_error_dict['unknown_error']
        else:
            error_msg = "REST API server on controller-node %s " % self.controller
            error_msg += "had %s error:\n" % rest_error_dict['error_type']
            error_msg += rest_error_dict['description']
        return error_msg
    
    #
    # --------------------------------------------------------------------------------
    # method_from_name
    #
    def method_from_name(self, name):
       return getattr(self, "validate_" + name.replace("-","_"), None)

    #
    # --------------------------------------------------------------------------------
    # validate_port
    #
    # - validate port foreign key (to switch)
    #
    def validate_port(self):
        error = None
        print "validate_port"

        # collect known switches
        switch_ids = None
        switch_key = self.obj_keys["switch"]
        try:
            switch_table = self.store.get_table_from_store("switch")
            switch_ids = [x[switch_key] for x in switch_table]
        except Exception, e:
            error = self.rest_error_to_dict(e)
            print self.rest_error_dict_to_message(error)
            pass
        
        if error:
            print "Unable to collect switch, no switch dpid validation for port table"
            error = None

        # collect known ports
        port_table = None
        port_key = self.obj_keys["port"]
        try:
            port_table = self.store.get_table_from_store("port")
        except Exception, e:
            error = self.rest_error_to_dict(e)
            print self.rest_error_dict_to_message(error)
            pass
class Validate():

    # initialize in init_obj_type_info
    obj_type_info_dict = {}  # see init_obj_type_info_dict
    obj_types = []
    obj_keys = {}

    known_controllers = ["127.0.0.1:8000"]
    controller = None
    # LOOK! manage this separately until we can for sure talk to eth0 addr instead of 127.0.0.1
    controller_for_prompt = "127.0.0.1:8000"
    cluster = "default"

    run = True

    # Cached options for last completion
    last_line = None
    last_options = None

    # Are we running in batch mode, i.e. "cat commands | cli.py"
    batch = False

    # used for parsing as an arg
    local_name_pattern = "localhost://([A-Za-z0-9_:@\-\.\/]+$)"

    # contained objects
    pp = None
    store = None
    model_handler = None

    #
    # --------------------------------------------------------------------------------
    # init_obj_type_info_dict
    #
    #  Builds the init_obj_type_info_dict, which is a dictionary indexed by
    #  the current mode, which also results in a dictionary, then indexed
    #  by a either a 'field' or 'field_ordering' key.
    #
    #  When init_obj_type_info_dict is indexed by the table/model name, the
    #  value is a dictionary.  That dictionary has several keys:
    #  - 'fields'
    #  - 'field_orderings'
    #
    #  The 'fields' indexed result returns a dictionary, each of which
    #  is indexed by the names of the fields within the table/model. further
    #  indicies describe details about that field within the table:
    #  - 'formatter' desscribes the prettyPrinter function for that field
    #  - 'primary_key' identifes this field as the key for the table/model.
    #  - 'verbose_name' identfies an additonal name for the field, inteneded
    #                   to be more descriptive
    #  - 'has_rest_model'  True/False
    #  - 'json_serialize_string'  True/False
    #  - 'help_text'  String providing more clues about the intent of this field
    #
    #  The 'field_ordering' dictionary associated with the name of the table/model
    #  is used to order the output.
    #
    #  Also populates the self.obj_keys[], which is a dictionary mapping the table/model
    #  name to the name of the storage key (table/model's column) for that table.
    #
    def init_obj_type_info_dict(self):
        self.cli_model_info = CliModelInfo()
        self.obj_type_info_dict = self.cli_model_info.get_complete_obj_type_info_dict(
        )
        self.obj_types = [
            k for (k, v) in self.obj_type_info_dict.items()
            if 'has_rest_model' in v
        ]
        for (k, d) in self.obj_type_info_dict.items():
            candidate_keys = [
                f for f in d['fields'].keys()
                if d['fields'][f].get('primary_key', False)
            ]
            if len(candidate_keys) > 0:
                self.obj_keys[k] = candidate_keys[0]

    #
    # --------------------------------------------------------------------------------
    # make_unit_formatter
    #
    def make_unit_formatter(self, units):
        return lambda x, y: '%s %s' % (x, units)

    #
    # --------------------------------------------------------------------------------
    # init_obj_type_info_dict
    #
    #  Builds the init_obj_type_info_dict, which is a dictionary indexed by
    #  the current mode, which also results in a dictionary, then indexed
    #  by a either a 'field' or 'field_ordering' key.
    #
    #  When init_obj_type_info_dict is indexed by the table/model name, the
    #  value is a dictionary.  That dictionary has several keys:
    #  - 'fields'
    #  - 'field_orderings'
    #
    #  The 'fields' indexed result returns a dictionary, each of which
    #  is indexed by the names of the fields within the table/model. further
    #  indicies describe details about that field within the table:
    #  - 'formatter' desscribes the prettyPrinter function for that field
    #  - 'primary_key' identifes this field as the key for the table/model.
    #  - 'verbose_name' identfies an additonal name for the field, inteneded
    #                   to be more descriptive
    #  - 'has_rest_model'  True/False
    #  - 'json_serialize_string'  True/False
    #  - 'help_text'  String providing more clues about the intent of this field
    #
    #  The 'field_ordering' dictionary associated with the name of the table/model
    #  is used to order the output.
    #
    #  Also populates the self.obj_keys[], which is a dictionary mapping the table/model
    #  name to the name of the storage key (table/model's column) for that table.
    #
    def init_obj_type_info_dict(self):
        self.cli_model_info = CliModelInfo()
        self.obj_type_info_dict = self.cli_model_info.get_complete_obj_type_info_dict(
        )
        self.obj_types = [
            k for (k, v) in self.obj_type_info_dict.items()
            if 'has_rest_model' in v
        ]
        for (k, d) in self.obj_type_info_dict.items():
            candidate_keys = [
                f for f in d['fields'].keys()
                if d['fields'][f].get('primary_key', False)
            ]
            if len(candidate_keys) > 0:
                self.obj_keys[k] = candidate_keys[0]

    #
    # --------------------------------------------------------------------------------
    # init
    #
    def init(self):

        self.vendordb = VendorDB()
        self.vendordb.init()

        parser = OptionParser()
        parser.add_option("-c",
                          "--controller",
                          dest="controller",
                          help="set default controller to CONTROLLER",
                          metavar="CONTROLLER",
                          default=self.controller)
        (options, args) = parser.parse_args()
        self.controller = options.controller
        if not self.controller:
            self.controller = "127.0.0.1:8000"

        if not sys.stdin.isatty():
            self.batch = True

        self.init_obj_type_info_dict()

        self.pp = PrettyPrinter(self.obj_type_info_dict)
        self.store = StoreClient()
        self.store.set_controller(self.controller)

    #
    # --------------------------------------------------------------------------------
    # parse_optional_parameters
    #
    def parse_optional_parameters(self, params, words):
        parsed = {}
        i = 0
        while i < len(words):
            word = words[i]
            possible = [x for x in params if x.startswith(word)]
            if len(possible) == 0:
                raise ParamException('unknown option: %s' % word)
            elif len(possible) > 1:
                raise ParamException('ambiguous option: %s\n%s' %
                                     (word, "\n".join(possible)))
            else:
                param_name = possible[0]
                param = params[param_name]
                if (param['type'] == 'flag'):
                    parsed[param_name] = True
                else:
                    if i + 1 < len(words):
                        argument = words[i + 1]
                        if (param['type'] == 'string'):
                            parsed[param_name] = argument
                        elif (param['type'] == 'int'):
                            try:
                                parsed[param_name] = int(argument)
                            except ValueError:
                                raise ParamException('option %s requires ' +
                                                     'integer argument' % word)
                        elif (param['type'] == 'enum'):
                            arg_possible = [
                                x for x in param['values']
                                if x.startswith(argument)
                            ]
                            if (len(arg_possible) == 0):
                                raise ParamException(
                                    'option %s value must be in (%s)' %
                                    (word, ", ".join(param['values'])))
                            elif (len(arg_possible) > 1):
                                raise ParamException(
                                    'ambiguous option %s value:\n%s' %
                                    (word, "\n".join(arg_possible)))
                            else:
                                parsed[param_name] = arg_possible[0]
                        i += 1
                    else:
                        raise ParamException('option %s requires an argument' %
                                             word)
            i += 1
        return parsed

    #
    # --------------------------------------------------------------------------------
    # rest_error_to_dict
    #   Turn an exception into an error dictionary, which can later be printed.
    #   using rest_error_dict_to_message().
    #
    def rest_error_to_dict(self, e, detail=None):
        errors = None
        # try to identifify validation requests
        if isinstance(e, httplib.BadStatusLine):
            errors = {
                'connection_error':
                'REST API server %s: '
                'server not running' % self.controller
            }
            return errors

        elif isinstance(e, urllib2.HTTPError):
            code = e.code
            error_returned = e.readline()

            if code == 404:
                if detail:
                    errors = {'not_found_error': 'Not Found: %s' % detail}
                else:
                    errors = {
                        'not_found_error': 'Not Found: %s' % error_returned
                    }
            elif code == 500 or code == 403:
                errors = {
                    'connection_error':
                    'REST API server %s unable to connect: '
                    'Cassandra possibly not running' % self.controller
                }
            elif code == 400:
                try:
                    errors = json.loads(error_returned)
                except:
                    # if the error can't be converted into a dictionary, then imbed the complete
                    # errors as the value for a specific error key.
                    errors = {
                        'error_result_error':
                        "Can't convert returned error: %s" % error_returned
                    }
                    pass
            else:
                errors = {'unknown_error': 'HttpError %s' % error_returned}
        else:
            errors = {
                'unknown_error': "Need error managmenet for error %s" % type(e)
            }

        return errors

    #
    # --------------------------------------------------------------------------------
    # rest_error_dict_to_message
    #   Turn an rest_error_dict returned from rest_error_to_dict
    #   into an error message which can ge printed.  Code assumes multiple errors
    #   won't occur; if a 'field_error' exists, for example, a 'model_error' won't
    #   also be posted in the error
    #
    def rest_error_dict_to_message(self, rest_error_dict):
        error_msg = ""
        if 'field_errors' in rest_error_dict:
            for (k, v) in rest_error_dict['field_errors'].items():
                error_msg += "Syntax error: field %s: %s" % (k, v)
            # traceback.print_stack(), to find out why the error occured
        elif 'model_error' in rest_error_dict:
            error_msg += "Error: %s" % rest_error_dict['model_error']
        elif 'not_found_error' in rest_error_dict:
            error_msg += "Error: %s" % rest_error_dict['not_found_error']
        elif 'connection_error' in rest_error_dict:
            error_msg += rest_error_dict['connection_error']
        elif 'error_result_error' in rest_error_dict:
            error_msg += rest_error_dict['error_result_error']
        elif 'unknown_error' in rest_error_dict:
            error_msg += rest_error_dict['unknown_error']
        else:
            error_msg = "REST API server on controller-node %s " % self.controller
            error_msg += "had %s error:\n" % rest_error_dict['error_type']
            error_msg += rest_error_dict['description']
        return error_msg

    #
    # --------------------------------------------------------------------------------
    # method_from_name
    #
    def method_from_name(self, name):
        return getattr(self, "validate_" + name.replace("-", "_"), None)

    #
    # --------------------------------------------------------------------------------
    # validate_port
    #
    # - validate port foreign key (to switch)
    #
    def validate_port(self):
        error = None
        print "validate_port"

        # collect known switches
        switch_ids = None
        switch_key = self.obj_keys["switch"]
        try:
            switch_table = self.store.get_table_from_store("switch")
            switch_ids = [x[switch_key] for x in switch_table]
        except Exception, e:
            error = self.rest_error_to_dict(e)
            print self.rest_error_dict_to_message(error)
            pass

        if error:
            print "Unable to collect switch, no switch dpid validation for port table"
            error = None

        # collect known ports
        port_table = None
        port_key = self.obj_keys["port"]
        try:
            port_table = self.store.get_table_from_store("port")
        except Exception, e:
            error = self.rest_error_to_dict(e)
            print self.rest_error_dict_to_message(error)
            pass