예제 #1
0
 def _generate_backup_contents(
     self,
     tar_file_path: Path,
     backup_data: dict[str, Any],
 ) -> None:
     """Generate backup contents."""
     with TemporaryDirectory() as tmp_dir, SecureTarFile(
         tar_file_path, "w", gzip=False
     ) as tar_file:
         tmp_dir_path = Path(tmp_dir)
         json_util.save_json(
             tmp_dir_path.joinpath("./backup.json").as_posix(),
             backup_data,
         )
         with SecureTarFile(
             tmp_dir_path.joinpath("./homeassistant.tar.gz").as_posix(),
             "w",
         ) as core_tar:
             atomic_contents_add(
                 tar_file=core_tar,
                 origin_path=Path(self.hass.config.path()),
                 excludes=EXCLUDE_FROM_BACKUP,
                 arcname="data",
             )
         tar_file.add(tmp_dir_path, arcname=".")
예제 #2
0
    async def restore_homeassistant(self) -> Awaitable[None]:
        """Restore Home Assitant Core configuration folder."""
        await self.sys_homeassistant.core.stop()

        # Restore Home Assistant Core config directory
        homeassistant_file = SecureTarFile(Path(self._tmp.name,
                                                "homeassistant.tar.gz"),
                                           "r",
                                           key=self._key)

        await self.sys_homeassistant.restore(homeassistant_file)

        # Generate restore task
        async def _core_update():
            try:
                if self.homeassistant_version == self.sys_homeassistant.version:
                    return
            except TypeError:
                # Home Assistant is not yet installed / None
                pass
            except AwesomeVersionCompareException as err:
                raise BackupError(
                    f"Invalid Home Assistant Core version {self.homeassistant_version}",
                    _LOGGER.error,
                ) from err
            await self.sys_homeassistant.core.update(self.homeassistant_version
                                                     )

        return self.sys_create_task(_core_update())
예제 #3
0
        def _folder_save(name: str):
            """Take backup of a folder."""
            slug_name = name.replace("/", "_")
            tar_name = Path(
                self._tmp.name,
                f"{slug_name}.tar{'.gz' if self.compressed else ''}")
            origin_dir = Path(self.sys_config.path_supervisor, name)

            # Check if exists
            if not origin_dir.is_dir():
                _LOGGER.warning("Can't find backup folder %s", name)
                return

            # Take backup
            _LOGGER.info("Backing up folder %s", name)
            with SecureTarFile(tar_name,
                               "w",
                               key=self._key,
                               gzip=self.compressed) as tar_file:
                atomic_contents_add(
                    tar_file,
                    origin_dir,
                    excludes=[],
                    arcname=".",
                )

            _LOGGER.info("Backup folder %s done", name)
            self._data[ATTR_FOLDERS].append(name)
예제 #4
0
 def _restore() -> None:
     try:
         _LOGGER.info("Restore folder %s", name)
         with SecureTarFile(tar_name,
                            "r",
                            key=self._key,
                            gzip=self.compressed) as tar_file:
             tar_file.extractall(path=origin_dir, members=tar_file)
         _LOGGER.info("Restore folder %s done", name)
     except (tarfile.TarError, OSError) as err:
         _LOGGER.warning("Can't restore folder %s: %s", name, err)
예제 #5
0
    async def store_homeassistant(self):
        """Backup Home Assitant Core configuration folder."""
        self._data[ATTR_HOMEASSISTANT] = {
            ATTR_VERSION: self.sys_homeassistant.version
        }

        # Backup Home Assistant Core config directory
        homeassistant_file = SecureTarFile(Path(self._tmp.name,
                                                "homeassistant.tar.gz"),
                                           "w",
                                           key=self._key)

        await self.sys_homeassistant.backup(homeassistant_file)

        # Store size
        self.homeassistant[ATTR_SIZE] = homeassistant_file.size
예제 #6
0
        async def _addon_restore(addon_slug: str):
            """Task to restore an add-on into backup."""
            tar_name = f"{addon_slug}.tar{'.gz' if self.compressed else ''}"
            addon_file = SecureTarFile(Path(self._tmp.name, tar_name),
                                       "r",
                                       key=self._key,
                                       gzip=self.compressed)

            # If exists inside backup
            if not addon_file.path.exists():
                _LOGGER.error("Can't find backup %s", addon_slug)
                return

            # Perform a restore
            try:
                await self.sys_addons.restore(addon_slug, addon_file)
            except AddonsError:
                _LOGGER.error("Can't restore backup %s", addon_slug)
예제 #7
0
async def test_fixup(coresys: CoreSys, tmp_path):
    """Test fixup."""
    clear_full_backup = FixupSystemClearFullBackup(coresys)

    assert not clear_full_backup.auto

    coresys.resolution.suggestions = Suggestion(
        SuggestionType.CLEAR_FULL_BACKUP, ContextType.SYSTEM)

    for slug in ["sn1", "sn2", "sn3", "sn4", "sn5"]:
        temp_tar = Path(tmp_path, f"{slug}.tar")
        with SecureTarFile(temp_tar, "w"):
            pass
        backup = Backup(coresys, temp_tar)
        backup._data = {  # pylint: disable=protected-access
            ATTR_SLUG: slug,
            ATTR_DATE: utcnow().isoformat(),
            ATTR_TYPE: BackupType.PARTIAL
            if "1" in slug or "5" in slug
            else BackupType.FULL,
        }
        coresys.backups._backups[backup.slug] = backup

    newest_full_backup = coresys.backups._backups["sn4"]

    assert newest_full_backup in coresys.backups.list_backups
    assert (len([
        x for x in coresys.backups.list_backups
        if x.sys_type == BackupType.FULL
    ]) == 3)

    await clear_full_backup()
    assert newest_full_backup in coresys.backups.list_backups
    assert (len([
        x for x in coresys.backups.list_backups
        if x.sys_type == BackupType.FULL
    ]) == 1)

    assert len(coresys.resolution.suggestions) == 0
예제 #8
0
        async def _addon_save(addon: Addon):
            """Task to store an add-on into backup."""
            tar_name = f"{addon.slug}.tar{'.gz' if self.compressed else ''}"
            addon_file = SecureTarFile(Path(self._tmp.name, tar_name),
                                       "w",
                                       key=self._key,
                                       gzip=self.compressed)

            # Take backup
            try:
                await addon.backup(addon_file)
            except AddonsError:
                _LOGGER.error("Can't create backup for %s", addon.slug)
                return

            # Store to config
            self._data[ATTR_ADDONS].append({
                ATTR_SLUG: addon.slug,
                ATTR_NAME: addon.name,
                ATTR_VERSION: addon.version,
                ATTR_SIZE: addon_file.size,
            })