示例#1
0
class Database(object):

    filename = constants.get_gateway_database_file()
    _db = SqliteDatabase(filename, pragmas={'foreign_keys': 1})

    # used to store database metrics (e.g. number of saves)
    _metrics = {}  # type: Dict[str,int]

    @classmethod
    def get_db(cls):
        return cls._db

    @classmethod
    def incr_metrics(cls, sender, incr=1):
        cls._metrics.setdefault(sender, 0)
        cls._metrics[sender] += incr

    @classmethod
    def get_models(cls):
        models = set()
        for (class_name,
             class_member) in inspect.getmembers(sys.modules[__name__],
                                                 inspect.isclass):
            if issubclass(class_member, BaseModel):
                models.add(class_member.__name__)
        return models

    @classmethod
    def get_metrics(cls):
        return cls._metrics
示例#2
0
 class Meta:
     database = SqliteDatabase(constants.get_gateway_database_file(),
                               pragmas={'foreign_keys': 1})
示例#3
0
    def restore_full_backup(self, data):
        """
        Restore a full backup containing the master eeprom and the sqlite databases.

        :param data: The backup to restore.
        :type data: Tar containing multiple files: master.eep, config.db, scheduled.db, power.db,
        eeprom_extensions.db, metrics.db and plugins as a string of bytes.
        :returns: dict with 'output' key.
        """
        import glob
        import shutil
        import tempfile
        import subprocess

        tmp_dir = tempfile.mkdtemp()
        tmp_sqlite_dir = '{0}/sqlite'.format(tmp_dir)
        try:
            with open('{0}/backup.tar'.format(tmp_dir), 'wb') as backup_file:
                backup_file.write(data)

            retcode = subprocess.call(
                'cd {0}; tar xf backup.tar'.format(tmp_dir), shell=True)
            if retcode != 0:
                raise Exception('The backup tar could not be extracted.')

            # Check if the sqlite db's are in a folder or not for backwards compatibility
            src_dir = tmp_sqlite_dir if os.path.isdir(
                tmp_sqlite_dir) else tmp_dir

            with open('{0}/master.eep'.format(src_dir), 'r') as eeprom_file:
                eeprom_content = eeprom_file.read()
                self.master_restore(eeprom_content)

            for filename, target in {
                    'config.db':
                    constants.get_config_database_file(),
                    'users.db':
                    constants.get_config_database_file(),
                    'power.db':
                    constants.get_power_database_file(),
                    'eeprom_extensions.db':
                    constants.get_eeprom_extension_database_file(),
                    'metrics.db':
                    constants.get_metrics_database_file(),
                    'gateway.db':
                    constants.get_gateway_database_file()
            }.items():
                source = '{0}/{1}'.format(src_dir, filename)
                if os.path.exists(source):
                    shutil.copyfile(source, target)

            # Restore the plugins if there are any
            backup_plugin_dir = '{0}/plugins'.format(tmp_dir)
            backup_plugin_content_dir = '{0}/content'.format(backup_plugin_dir)
            backup_plugin_config_files = '{0}/config/pi_*'.format(
                backup_plugin_dir)

            if os.path.isdir(backup_plugin_dir):
                plugin_dir = constants.get_plugin_dir()
                plugins = [
                    name for name in os.listdir(backup_plugin_content_dir)
                    if os.path.isdir(
                        os.path.join(backup_plugin_content_dir, name))
                ]
                for plugin in plugins:
                    dest_dir = '{0}{1}'.format(plugin_dir, plugin)
                    if os.path.isdir(dest_dir):
                        shutil.rmtree(dest_dir)
                    shutil.copytree(
                        '{0}/{1}/'.format(backup_plugin_content_dir, plugin),
                        '{0}{1}'.format(plugin_dir, plugin))

                config_files = constants.get_plugin_config_dir()
                for config_file in glob.glob(backup_plugin_config_files):
                    shutil.copy(config_file, '{0}/'.format(config_files))

            return {'output': 'Restore complete'}

        finally:
            shutil.rmtree(tmp_dir)
            # Restart the Cherrypy server after 1 second. Lets the current request terminate.
            threading.Timer(1, lambda: os._exit(0)).start()
示例#4
0
    def get_full_backup(self):
        """
        Get a backup (tar) of the master eeprom, the sqlite databases and the plugins

        :returns: Tar containing multiple files: master.eep, config.db, scheduled.db, power.db,
        eeprom_extensions.db, metrics.db and plugins as a string of bytes.
        """
        _ = self  # Not static for consistency

        def backup_sqlite_db(input_db_path, backup_db_path):
            """ Backup an sqlite db provided the path to the db to backup and the backup db. """
            # Connect to database
            connection = sqlite3.connect(input_db_path)
            cursor = connection.cursor()

            # Lock database before making a backup
            cursor.execute('begin immediate')

            # Make new backup file
            shutil.copyfile(input_db_path, backup_db_path)

            # Unlock database
            connection.rollback()

        tmp_dir = tempfile.mkdtemp()
        tmp_sqlite_dir = '{0}/sqlite'.format(tmp_dir)
        os.mkdir(tmp_sqlite_dir)

        try:
            with open('{0}/master.eep'.format(tmp_sqlite_dir),
                      'w') as eeprom_file:
                eeprom_file.write(self.get_master_backup())

            for filename, source in {
                    'config.db':
                    constants.get_config_database_file(),
                    'power.db':
                    constants.get_power_database_file(),
                    'eeprom_extensions.db':
                    constants.get_eeprom_extension_database_file(),
                    'metrics.db':
                    constants.get_metrics_database_file(),
                    'gateway.db':
                    constants.get_gateway_database_file()
            }.items():
                if os.path.exists(source):
                    target = '{0}/{1}'.format(tmp_sqlite_dir, filename)
                    backup_sqlite_db(source, target)

            # Backup plugins
            tmp_plugin_dir = '{0}/{1}'.format(tmp_dir, 'plugins')
            tmp_plugin_content_dir = '{0}/{1}'.format(tmp_plugin_dir,
                                                      'content')
            tmp_plugin_config_dir = '{0}/{1}'.format(tmp_plugin_dir, 'config')
            os.mkdir(tmp_plugin_dir)
            os.mkdir(tmp_plugin_content_dir)
            os.mkdir(tmp_plugin_config_dir)

            plugin_dir = constants.get_plugin_dir()
            plugins = [
                name for name in os.listdir(plugin_dir)
                if os.path.isdir(os.path.join(plugin_dir, name))
            ]
            for plugin in plugins:
                shutil.copytree(
                    plugin_dir + plugin,
                    '{0}/{1}/'.format(tmp_plugin_content_dir, plugin))

            config_files = constants.get_plugin_configfiles()
            for config_file in glob.glob(config_files):
                shutil.copy(config_file, '{0}/'.format(tmp_plugin_config_dir))

            # Backup hex files
            tmp_hex_dir = '{0}/{1}'.format(tmp_dir, 'hex')
            os.mkdir(tmp_hex_dir)
            hex_files = constants.get_hex_files()
            for hex_file in glob.glob(hex_files):
                shutil.copy(hex_file, '{0}/'.format(tmp_hex_dir))

            # Backup general config stuff
            tmp_config_dir = '{0}/{1}'.format(tmp_dir, 'config')
            os.mkdir(tmp_config_dir)
            config_dir = constants.get_config_dir()
            for file_name in ['openmotics.conf', 'https.key', 'https.crt']:
                shutil.copy(os.path.join(config_dir, file_name),
                            '{0}/'.format(tmp_config_dir))

            retcode = subprocess.call(
                'cd {0}; tar cf backup.tar *'.format(tmp_dir), shell=True)
            if retcode != 0:
                raise Exception('The backup tar could not be created.')

            with open('{0}/backup.tar'.format(tmp_dir), 'r') as backup_file:
                return backup_file.read()

        finally:
            shutil.rmtree(tmp_dir)