From 33ef3fca93b8c3bb2c220f8d3240f71eb42b84ad Mon Sep 17 00:00:00 2001 From: "Sebastian M. Ernst" Date: Wed, 22 Jul 2020 20:57:03 +0200 Subject: [PATCH 01/12] new release cycle --- CHANGES.md | 4 ++++ setup.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 5113087..343df26 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,9 @@ # Changes +## 0.0.5 (2020-XX-XX) + +- (TBD) + ## 0.0.4 (2020-07-22) - FEATURE: Improved labels in wizard GUI diff --git a/setup.py b/setup.py index df9c1d1..b5365ae 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Package version -__version__ = "0.0.4" +__version__ = "0.0.5" # List all versions of Python which are supported python_minor_min = 6 From 1c07fccd6403bd5cd9bfa98b059a558b496048e5 Mon Sep 17 00:00:00 2001 From: "Sebastian M. Ernst" Date: Fri, 24 Jul 2020 10:36:35 +0200 Subject: [PATCH 02/12] moved version into package --- setup.py | 5 ++--- src/abgleich/__init__.py | 6 ++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index b5365ae..53d1708 100644 --- a/setup.py +++ b/setup.py @@ -35,13 +35,12 @@ ) import os +from abgleich import __version__ + # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # SETUP # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -# Package version -__version__ = "0.0.5" - # List all versions of Python which are supported python_minor_min = 6 python_minor_max = 8 diff --git a/src/abgleich/__init__.py b/src/abgleich/__init__.py index 97275ca..d9e5eec 100644 --- a/src/abgleich/__init__.py +++ b/src/abgleich/__init__.py @@ -23,3 +23,9 @@ """ + +# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# META +# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +__version__ = "0.0.5" From 23c28c61abf5163d3d14b1664441399043b265db Mon Sep 17 00:00:00 2001 From: "Sebastian M. Ernst" Date: Fri, 24 Jul 2020 10:38:18 +0200 Subject: [PATCH 03/12] show version in gui --- src/abgleich/gui/wizard.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/abgleich/gui/wizard.py b/src/abgleich/gui/wizard.py index 44d0476..5e446b6 100644 --- a/src/abgleich/gui/wizard.py +++ b/src/abgleich/gui/wizard.py @@ -40,6 +40,7 @@ from ..core.transaction import TransactionList from ..core.i18n import t from ..core.zpool import Zpool +from .. import __version__ # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # CLASS @@ -56,7 +57,7 @@ def __init__(self, config: ConfigABC): self.setWindowIcon( QIcon(os.path.join(os.path.dirname(__file__), "..", "share", "icon.svg")) ) - self.setWindowTitle(t("abgleich wizard")) + self.setWindowTitle(f'{t("abgleich wizard"):s} {__version__:s}') self._ui["button_cancel"].setEnabled(False) self._ui["button_continue"].setEnabled(False) From b660c1ce6b49cf19e06f93265546a3e931b41747 Mon Sep 17 00:00:00 2001 From: "Sebastian M. Ernst" Date: Fri, 24 Jul 2020 10:45:53 +0200 Subject: [PATCH 04/12] expose version on command line --- src/abgleich/cli/_main_.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/abgleich/cli/_main_.py b/src/abgleich/cli/_main_.py index 43a6572..f8612af 100644 --- a/src/abgleich/cli/_main_.py +++ b/src/abgleich/cli/_main_.py @@ -31,9 +31,12 @@ import importlib import os +import sys import click +from .. import __version__ + # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # ROUTINES # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -54,9 +57,16 @@ def _add_commands(ctx): continue -@click.group() -def cli(): +@click.group(invoke_without_command=True) +@click.option('--version', is_flag=True) +def cli(version): """abgleich, zfs sync tool""" + if not version: + return + + print(__version__) + sys.exit() + _add_commands(cli) From 377eda96363cb2b4112ba8ef459f20d06c1c18d8 Mon Sep 17 00:00:00 2001 From: "Sebastian M. Ernst" Date: Fri, 24 Jul 2020 10:46:45 +0200 Subject: [PATCH 05/12] logged changes --- CHANGES.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 343df26..0298935 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,7 +2,8 @@ ## 0.0.5 (2020-XX-XX) -- (TBD) +- FEATURE: Version shown in GUI +- FEATURE: Version exposed through `--version` option on command line ## 0.0.4 (2020-07-22) From 32717d5e3260a61c32a98cf7dc782d96e42be1e8 Mon Sep 17 00:00:00 2001 From: "Sebastian M. Ernst" Date: Fri, 24 Jul 2020 11:11:46 +0200 Subject: [PATCH 06/12] black --- src/abgleich/cli/_main_.py | 2 +- src/abgleich/core/dataset.py | 5 ++--- src/abgleich/core/i18n.py | 4 +--- src/abgleich/core/zpool.py | 5 ++++- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/abgleich/cli/_main_.py b/src/abgleich/cli/_main_.py index f8612af..4512286 100644 --- a/src/abgleich/cli/_main_.py +++ b/src/abgleich/cli/_main_.py @@ -58,7 +58,7 @@ def _add_commands(ctx): @click.group(invoke_without_command=True) -@click.option('--version', is_flag=True) +@click.option("--version", is_flag=True) def cli(version): """abgleich, zfs sync tool""" diff --git a/src/abgleich/core/dataset.py b/src/abgleich/core/dataset.py index 913c439..16ac245 100644 --- a/src/abgleich/core/dataset.py +++ b/src/abgleich/core/dataset.py @@ -90,9 +90,8 @@ def get( if isinstance(key, str): return self._properties.get( - key, - Property(key, None, None) if default is None else default, - ) + key, Property(key, None, None) if default is None else default, + ) assert isinstance(key, int) or isinstance(key, slice) diff --git a/src/abgleich/core/i18n.py b/src/abgleich/core/i18n.py index 2bc34ef..09b5ec9 100644 --- a/src/abgleich/core/i18n.py +++ b/src/abgleich/core/i18n.py @@ -85,9 +85,7 @@ def _load(self): def _dump(self): with open(self._path, "w") as f: - f.write( - yaml.dump(self.copy(), Dumper=Dumper, allow_unicode=True, indent=4) - ) + f.write(yaml.dump(self.copy(), Dumper=Dumper, allow_unicode=True, indent=4)) # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/src/abgleich/core/zpool.py b/src/abgleich/core/zpool.py index 71e9803..eec3ea7 100644 --- a/src/abgleich/core/zpool.py +++ b/src/abgleich/core/zpool.py @@ -254,7 +254,10 @@ def _get_snapshot_transactions_from_dataset( if dataset.subname in self._config["ignore"]: return - if dataset.get("mountpoint").value is None and dataset['type'].value == 'filesystem': + if ( + dataset.get("mountpoint").value is None + and dataset["type"].value == "filesystem" + ): return if not dataset.changed: return From 77bc9b1231e4995a3eaee2c26d40f1a0e9d6f9aa Mon Sep 17 00:00:00 2001 From: "Sebastian M. Ernst" Date: Fri, 24 Jul 2020 11:37:42 +0200 Subject: [PATCH 07/12] fix 14 new configuration parameter include_root --- src/abgleich/core/zpool.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/abgleich/core/zpool.py b/src/abgleich/core/zpool.py index eec3ea7..9c4b596 100644 --- a/src/abgleich/core/zpool.py +++ b/src/abgleich/core/zpool.py @@ -361,18 +361,10 @@ def available(side: str, config: ConfigABC,) -> int: @classmethod def from_config(cls, side: str, config: ConfigABC,) -> ZpoolABC: + root_dataset = root(config[side]["zpool"], config[side]["prefix"]) + output, _ = Command.on_side( - [ - "zfs", - "get", - "all", - "-r", - "-H", - "-p", - root(config[side]["zpool"], config[side]["prefix"]), - ], - side, - config, + ["zfs", "get", "all", "-r", "-H", "-p", root_dataset,], side, config, ).run() output = [ line.split("\t") for line in output.split("\n") if len(line.strip()) > 0 @@ -381,6 +373,15 @@ def from_config(cls, side: str, config: ConfigABC,) -> ZpoolABC: for line_list in output: entities[line_list[0]].append(line_list[1:]) + if not config.get("include_root", True): + entities.pop(root_dataset) + for name in [ + snapshot + for snapshot in entities.keys() + if snapshot.startswith(f"{root_dataset:s}@") + ]: + entities.pop(name) + datasets = [ Dataset.from_entities( name, From d4ea8114122de147df2587be4cfc20a9a7c57a99 Mon Sep 17 00:00:00 2001 From: "Sebastian M. Ernst" Date: Fri, 24 Jul 2020 11:39:21 +0200 Subject: [PATCH 08/12] logged changes --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 0298935..fb4ce59 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,6 +4,7 @@ - FEATURE: Version shown in GUI - FEATURE: Version exposed through `--version` option on command line +- FEATURE: While `{zpool}{/{prefix}}` is included in all operations by default, this can be deactivated by setting the new `include_root` configuration option to `no`, see #14. ## 0.0.4 (2020-07-22) From 163d5493dadf962f2ea58f015c48973c1506977c Mon Sep 17 00:00:00 2001 From: "Sebastian M. Ernst" Date: Fri, 24 Jul 2020 11:52:29 +0200 Subject: [PATCH 09/12] expose returncode --- src/abgleich/core/command.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/abgleich/core/command.py b/src/abgleich/core/command.py index 94d9bf8..bdbcbea 100644 --- a/src/abgleich/core/command.py +++ b/src/abgleich/core/command.py @@ -50,7 +50,9 @@ def __str__(self) -> str: return " ".join([item.replace(" ", "\\ ") for item in self._cmd]) - def run(self): + def run( + self, returncode: bool = False + ) -> typing.Union[typing.Tuple[str, str], typing.Tuple[str, str, int]]: proc = subprocess.Popen( self.cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE @@ -59,6 +61,9 @@ def run(self): status = not bool(proc.returncode) output, errors = output.decode("utf-8"), errors.decode("utf-8") + if returncode: + return output, errors, int(proc.returncode) + if not status or len(errors.strip()) > 0: raise SystemError("command failed", str(self), output, errors) From 4e206d1b339a829638e5b896b584eeb9685cbd2d Mon Sep 17 00:00:00 2001 From: "Sebastian M. Ernst" Date: Fri, 24 Jul 2020 12:18:08 +0200 Subject: [PATCH 10/12] fix 15: always check if all relevant hosts are up --- src/abgleich/cli/backup.py | 7 +++++++ src/abgleich/cli/cleanup.py | 7 +++++++ src/abgleich/cli/compare.py | 8 ++++++++ src/abgleich/cli/snap.py | 10 +++++++++- src/abgleich/cli/tree.py | 11 ++++++++++- src/abgleich/core/lib.py | 15 +++++++++++++++ src/abgleich/share/translations.yaml | 2 ++ 7 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/abgleich/cli/backup.py b/src/abgleich/cli/backup.py index 74303a2..33c3faf 100644 --- a/src/abgleich/cli/backup.py +++ b/src/abgleich/cli/backup.py @@ -30,9 +30,11 @@ # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ import click +import sys from ..core.config import Config from ..core.i18n import t +from ..core.lib import is_host_up from ..core.zpool import Zpool # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -46,6 +48,11 @@ def backup(configfile): config = Config.from_fd(configfile) + for side in ("source", "target"): + if not is_host_up(side, config): + print(f'{t("host is not up"):s}: {side:s}') + sys.exit(1) + source_zpool = Zpool.from_config("source", config=config) target_zpool = Zpool.from_config("target", config=config) diff --git a/src/abgleich/cli/cleanup.py b/src/abgleich/cli/cleanup.py index 52a08d1..68803fd 100644 --- a/src/abgleich/cli/cleanup.py +++ b/src/abgleich/cli/cleanup.py @@ -30,12 +30,14 @@ # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ import time +import sys import click from ..core.config import Config from ..core.i18n import t from ..core.io import humanize_size +from ..core.lib import is_host_up from ..core.zpool import Zpool # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -49,6 +51,11 @@ def cleanup(configfile): config = Config.from_fd(configfile) + for side in ("source", "target"): + if not is_host_up(side, config): + print(f'{t("host is not up"):s}: {side:s}') + sys.exit(1) + source_zpool = Zpool.from_config("source", config=config) target_zpool = Zpool.from_config("target", config=config) available_before = Zpool.available("source", config=config) diff --git a/src/abgleich/cli/compare.py b/src/abgleich/cli/compare.py index 18afc6a..d74588c 100644 --- a/src/abgleich/cli/compare.py +++ b/src/abgleich/cli/compare.py @@ -30,8 +30,11 @@ # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ import click +import sys from ..core.config import Config +from ..core.i18n import t +from ..core.lib import is_host_up from ..core.zpool import Zpool # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -45,6 +48,11 @@ def compare(configfile): config = Config.from_fd(configfile) + for side in ("source", "target"): + if not is_host_up(side, config): + print(f'{t("host is not up"):s}: {side:s}') + sys.exit(1) + source_zpool = Zpool.from_config("source", config=config) target_zpool = Zpool.from_config("target", config=config) diff --git a/src/abgleich/cli/snap.py b/src/abgleich/cli/snap.py index a2d62f9..b228341 100644 --- a/src/abgleich/cli/snap.py +++ b/src/abgleich/cli/snap.py @@ -30,9 +30,11 @@ # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ import click +import sys from ..core.config import Config from ..core.i18n import t +from ..core.lib import is_host_up from ..core.zpool import Zpool # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -44,7 +46,13 @@ @click.argument("configfile", type=click.File("r", encoding="utf-8")) def snap(configfile): - zpool = Zpool.from_config("source", config=Config.from_fd(configfile)) + config = Config.from_fd(configfile) + + if not is_host_up("source", config): + print(f'{t("host is not up"):s}: source') + sys.exit(1) + + zpool = Zpool.from_config("source", config=config) transactions = zpool.get_snapshot_transactions() if len(transactions) == 0: diff --git a/src/abgleich/cli/tree.py b/src/abgleich/cli/tree.py index 9ff9eba..8558d73 100644 --- a/src/abgleich/cli/tree.py +++ b/src/abgleich/cli/tree.py @@ -30,8 +30,11 @@ # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ import click +import sys from ..core.config import Config +from ..core.i18n import t +from ..core.lib import is_host_up from ..core.zpool import Zpool # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -44,5 +47,11 @@ @click.argument("side", default="source", type=str) def tree(configfile, side): - zpool = Zpool.from_config(side, config=Config.from_fd(configfile)) + config = Config.from_fd(configfile) + + if not is_host_up("source", config): + print(f'{t("host is not up"):s}: source') + sys.exit(1) + + zpool = Zpool.from_config(side, config=config) zpool.print_table() diff --git a/src/abgleich/core/lib.py b/src/abgleich/core/lib.py index 167e803..76632a5 100644 --- a/src/abgleich/core/lib.py +++ b/src/abgleich/core/lib.py @@ -33,11 +33,26 @@ import typeguard +from .abc import ConfigABC +from .command import Command + # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ # ROUTINES # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +@typeguard.typechecked +def is_host_up(side: str, config: ConfigABC) -> bool: + + assert side in ("source", "target") + if config[side]["host"] == "localhost": + return True + + _, _, returncode = Command.on_side(["exit"], side, config).run(returncode=True) + assert returncode in (0, 255) + return returncode == 0 + + @typeguard.typechecked def join(*args: str) -> str: diff --git a/src/abgleich/share/translations.yaml b/src/abgleich/share/translations.yaml index 60f04d0..c7f4131 100644 --- a/src/abgleich/share/translations.yaml +++ b/src/abgleich/share/translations.yaml @@ -87,6 +87,8 @@ dataset_subname: de_SE: Datensatz-Namensfragment de: Name des Datensatzes en: Name of dataset +host is not up: + de: Computer ist nicht erreichbar nothing to do: de: nichts zu tun snapshot: From a6a984b6f7799a6ee49aa55c02b1b2bf7c89e7ac Mon Sep 17 00:00:00 2001 From: "Sebastian M. Ernst" Date: Fri, 24 Jul 2020 12:20:03 +0200 Subject: [PATCH 11/12] log changes --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index fb4ce59..024c7b8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,7 @@ - FEATURE: Version shown in GUI - FEATURE: Version exposed through `--version` option on command line - FEATURE: While `{zpool}{/{prefix}}` is included in all operations by default, this can be deactivated by setting the new `include_root` configuration option to `no`, see #14. +- FIX: If a remote host is not up, provide a proper error and fail gracefully, see #15. ## 0.0.4 (2020-07-22) From 3e955526f38c4e447b0a0f6c751d5121f7ce3453 Mon Sep 17 00:00:00 2001 From: "Sebastian M. Ernst" Date: Fri, 24 Jul 2020 15:47:41 +0200 Subject: [PATCH 12/12] prepare for release --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 024c7b8..53fae85 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,6 @@ # Changes -## 0.0.5 (2020-XX-XX) +## 0.0.5 (2020-07-24) - FEATURE: Version shown in GUI - FEATURE: Version exposed through `--version` option on command line