예제 #1
0
    def get_database_as_json(self,
                             path_string,
                             database='config',
                             separator='/',
                             pretty=False):
        answer = {'root': {}}
        path = decode_path_string(path_string, separator=separator)

        self.log.trace('GET_CURLY_VIEW %s' % (self.map))
        for data in self.map:
            if database == 'config':
                self.log.trace('GET_CURLY_VIEW_CFG %s' % (data))
                db = self.map[data]['config']
            else:
                self.log.trace('GET_CURLY_VIEW_OPER %s' % (data))
                db = self.map[data]['oper']

            path_to_sub_datastore = decode_path_string(data, separator='/')
            try:
                data_from_sub_datastore = dpath.util.get(
                    db.db, path_to_sub_datastore)
                dpath.util.new(answer, path_to_sub_datastore,
                               data_from_sub_datastore)
            except KeyError:
                pass

            if pretty:
                if len(answer['root']) == 0:
                    return 'Database is blank!'
                return json.dumps(answer['root'], indent=4, sort_keys=True)
            return json.dumps(answer, indent=4, sort_keys=True)
예제 #2
0
    def test_decode_path_string(self):
        result = decode_path_string('/x/1/2/3{abc}', separator='/')
        self.assertEqual(['root', 'x', '1', '2', '3', '{abc}'], result)

        result = decode_path_string('/x/1/2/3{abc}/x{def}', separator='/')
        self.assertEqual(['root', 'x', '1', '2', '3', '{abc}', 'x', '{def}'],
                         result)
예제 #3
0
    def set_from_string(self, full_string, database='config', command=''):
        """
        A convenience function to split apart the path, command and value
        and then call the set function.
        """

        value = decode_path_string(full_string[len(command):], get_index=-1)
        path = decode_path_string(full_string[:-len(value) - 1])
        self.set(path, value, database, separator=' ')
예제 #4
0
    def _add_to_list(self,
                     db,
                     node_type,
                     path_string,
                     list_keys,
                     separator=' '):
        path = decode_path_string(path_string, separator)
        list_element = dpath.util.get(self.schema, path)
        if not len(list_keys) == len(
                list_element['__listelement']['__schema']['__keys']):
            raise PyConfHoardWrongKeys(
                path, list_element['__listelement']['__schema']['__keys'])

        # string_composite_key = '{'
        string_composite_key = ''
        lk = 0
        for list_key in list_element['__listelement']['__schema']['__keys']:
            string_composite_key = string_composite_key + list_keys[lk] + ' '
            lk = lk + 1
        # string_composite_key = string_composite_key[:-1] + '}'
        string_composite_key = string_composite_key[:-1]

        path.append('{' + string_composite_key + '}')
        lk = 0
        for list_key in list_element['__listelement']['__schema']['__keys']:
            path.append(list_key)
            self.keyval[path_string + '{' + list_keys[lk] + '}/' +
                        list_key] = list_keys[lk]
            dpath.util.new(db, path, list_keys[lk])
            path.pop()
            lk = lk + 1

        self._create_new_list_element_in_schema(path, string_composite_key)
예제 #5
0
    def set(self, path, set_val, separator=' '):
        """Set the value of a leaf node.
        
        This function requires a decoded path as a string
        e.g. ['root', 'brewhouse', 'temperature', 'mash', 'setpoint'] -> 65

        TODO: This needs to validate against the schema!
        """
        path_string = convert_path_to_slash_string(path)
        self.log.trace('%s -> %s (separator %s)', path_string, set_val,
                       separator)
        node_type = self.get_type(path_string, '/')

        self.log.trace('%s VALIDATE %s' % (path_string, node_type))
        set_val = self.validate_against_schema({'__schema': node_type},
                                               set_val, path_string)
        self.keyval[path_string] = set_val

        regex = re.compile("{([A-Za-z0-9]*)}\/?")
        path_string = regex.sub('/{\g<1>}/', path_string)

        self.log.trace('updated patH_string inside set %s' % (path_string))
        path = decode_path_string(path_string, separator)
        self.log.trace('%s %s' % (path, set_val))
        self.log.trace('%s' % (self.db))
        dpath.util.new(self.db, path, set_val, separator='/')
        print(self.db)
        print(self.keyval)
예제 #6
0
 def list(self, path_string, separator=' '):
     """
     Shows structure of the databas
     """
     self.log.trace('%s LIST' % (path_string))
     path = decode_path_string(path_string, separator)
     return fetch_keys_from_path(self.schema, path)
예제 #7
0
    def register(self,
                 path_string,
                 appname,
                 readonly=False,
                 skip_schema_load=False):
        """
        This method will registers a configuration/oper datastores at a specifc
        part of the database.
        """
        if str(path_string) in self.map:
            raise PyConfHoardPathAlreadyRegistered(path_string)

        path = decode_path_string(path_string, separator='/')

        thisconfig = PyConfHoardDatastore()
        thisoper = PyConfHoardDatastore()
        thisconfig.id = appname
        thisconfig.config = True
        thisoper.id = appname
        thisoper.config = False

        if not skip_schema_load:
            thisconfig.load_blank_schema(self.config_schema)
            thisoper.load_blank_schema(self.oper_schema)
        dpath.util.new(self.config.db, path, thisconfig)
        dpath.util.new(self.oper.db, path, thisoper)

        self.map[path_string] = {'config': thisconfig, 'oper': thisoper}

        thisconfig.readonly = False
        thisoper.readonly = False

        return (thisconfig, thisoper)
예제 #8
0
    def list(self, path_string, database=None, separator=' '):
        try:
            data = self._lookup_datastore(path_string, separator=separator)
        except PyConfHoardDataPathNotRegistered as err:
            if database == 'config':
                data = self.config
            else:
                data = self.oper

        self.log.trace('Using instance %s for list operation' % (data))
        if isinstance(path_string, list):
            path = path_string
        else:
            path = decode_path_string(path_string, separator=separator)

        if database is None or database == 'config':
            try:
                return self.config.list(path_string, separator)
            except:
                pass

        if database is None or database == 'oper':
            try:
                return self.oper.list(path_string, separator)
            except:
                pass

        raise PyConfHoardDataPathDoesNotExist(path_string)
예제 #9
0
    def _auto_complete(self,
                       line,
                       text,
                       cmd='show ',
                       config=True,
                       filter_blank_values=False):
        """
        line     - the full line of text (e.g. show fermentation
        text     - the text fragment autom completing (e.g. fermentation)

        Note: cmd2 will swallow any exceptions and the command-line-completion
        won't behave as we expect.

        Examples:

            line            text        result
            'show '         ''          ['brewhouse ' ', 'ingredients ', 'recipes ']
            'show br'       'br'        ['brewhouse ']

            if text = '' then we search datastore for the full pth
            if text != '' then we have to search the datastore for everything except the prtial element.


        """
        if config:
            database = 'config'
        else:
            database = 'oper'

        try:
            strip_partial_elements = 0
            # Attempt to get the path which might not exist
            cmds = []
            try:
                if not text == '':
                    strip_partial_elements = 1
                path_to_find = decode_path_string(
                    line[len(cmd):],
                    ignore_last_n=strip_partial_elements,
                    ignore_root=True)
                slash_path = convert_path_to_slash_string(path_to_find)

                xcmds = self.pyconfhoarddata.list(path_to_find, separator='/')
                cmds = []
                for key in xcmds:
                    if key[0:len(text)] == text:
                        cmds.append(key + ' ')
            except Exception as err:
                print(traceback.format_exc())
                print(str(err)), '<auto-complete inner'
                pass
            cmds.sort()
        except Exception as err:
            print(traceback.format_exc())
            print(str(err))
            pass
        return cmds
예제 #10
0
 def _command_conf_show(self, args):
     'Show node in the configuration database'
     path = decode_path_string(args)
     try:
         print(
             self.pyconfhoarddata.get_database_as_json(path,
                                                       database='config',
                                                       pretty=True))
         self._ok()
     except Exception as err:
         self._error(err)
예제 #11
0
    def get(self, path_string, separator=' '):
        """
        Get the value of a node from either the datastore, this returns
        whatever object type is requested. For accessing simple data
        get_keypath is quicker..
        """
        node_type = self.get_type(path_string, separator)
        path = decode_path_string(path_string, separator)
        try:
            return dpath.util.get(self.db, path)
        except KeyError:
            pass

        return None
예제 #12
0
    def get_type(self, path_string, separator=' '):
        """
        Return the type of a particular leaf from the model.
        """
        self.log.trace('%s TYPE (separator %s)', path_string, separator)
        regex = re.compile("{([A-Za-z0-9]*)}\/?")
        path_string = regex.sub('/__listelement/', path_string)
        path = decode_path_string(path_string, separator)
        schema = dpath.util.get(self.schema, path)

        if '__listelement' in schema:
            return schema['__listelement']['__schema']
        elif '__schema' in schema:
            return schema['__schema']
        else:
            raise PyConfHoardAccessNonLeaf(path)
예제 #13
0
    def _merge_keyval(self, key, val):
        self.log.trace('%s <- %s', key, val)

        # Get the schema.
        regex = re.compile("{([A-Za-z0-9]*)}\/?")
        updated_key = regex.sub('/__listelement/', key)
        if not updated_key[0:5] == '/root':
            updated_key = '/root' + updated_key

        if updated_key not in self.schema_by_path:
            try:
                schema = dpath.util.get(self.schema, updated_key)
                self.schema_by_path[updated_key] = self.schema
            except KeyError:
                raise PyConfHoardDataNoLongerRequired(updated_key)
        else:
            schema = self.schema_by_path[updated_key]

        val = self.validate_against_schema(schema, val, key)

        dpath.util.new(self.db, updated_key, val)
        self.keyval[key] = val

        # TODO: if we pass the schema we have to add into self.db
        # First cover off the simple case without lists, although
        # what we have done so far won't have made it harder.
        index = 0
        if '__listelement' in updated_key:
            keys_in_path = regex.findall(key)
            path_to_work_on = updated_key
            for key_in_path in keys_in_path:
                # strip everything to the right of this key
                found_index = path_to_work_on.find('__listelement')
                left_part_of_key = path_to_work_on[0:found_index]
                right_part_of_key = path_to_work_on[found_index +
                                                    len('__listelement'):]

                path = decode_path_string(left_part_of_key, separator='/')
                path.append(key_in_path)
                self._create_new_list_element_in_schema(path, key_in_path)

                path_to_work_on = left_part_of_key + key_in_path + '/' + right_part_of_key
예제 #14
0
    def _lookup_datastore(self, path_string, database='config', separator='/'):
        path = decode_path_string(path_string,
                                  separator=separator,
                                  return_as_slash=True)
        if path == "/root":
            if database == 'config':
                return self.config
            else:
                return self.oper

        if path in self.map:
            return self.map[path][database]

        self.log.trace('MAP want %s: have: %s' % (path, self.map))
        for data in self.map:
            path_trimmed = path[0:len(data)]
            if path_trimmed == data:
                return self.map[data][database]

        raise PyConfHoardDataPathNotRegistered(path_string)
예제 #15
0
 def get_fragment(self, path_string, separator=' '):
     db = self.db
     path = decode_path_string(path_string, separator)
     fragment = dpath.util.get(db, path)
     return json.dumps(fragment, indent=4, sort_keys=True)
예제 #16
0
 def _command_create(self, args):
     path_to_list = decode_path_string(args, ignore_last_n=1)
     key = decode_path_string(args, get_index=-1)
     self.config.create(path_to_list, key)