From d78cbc8ef9032064d50662b61927b2b3449da90a Mon Sep 17 00:00:00 2001 From: themylogin Date: Wed, 1 May 2019 19:30:43 +0200 Subject: [PATCH 1/5] Take samba4 db backup before upgrade --- src/middlewared/middlewared/plugins/update.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/middlewared/middlewared/plugins/update.py b/src/middlewared/middlewared/plugins/update.py index 24498d7a4c73..c1532ffd7f78 100644 --- a/src/middlewared/middlewared/plugins/update.py +++ b/src/middlewared/middlewared/plugins/update.py @@ -2,6 +2,7 @@ from middlewared.schema import accepts, Bool, Dict, Str from middlewared.service import job, private, CallError, Service +from datetime import datetime import enum import errno import os @@ -456,6 +457,15 @@ async def update(self, job, attrs=None): ) await self.middleware.call('cache.put', 'update.applied', True) + if ( + await self.middleware.call_sync('system.is_freenas') or + ( + await self.middleware.call('failover.licensed') and + await self.middleware.call('failover.status') != 'BACKUP' + ) + ): + await self.middleware.call('update.take_systemdataset_samba4_snapshot') + if attrs.get('reboot'): await self.middleware.call('system.reboot', {'delay': 10}) return True @@ -645,3 +655,25 @@ def destroy_upload_location(self): ) if cp.returncode != 0: raise CallError(f'Could not destroy memory device: {cp.stderr}') + + @private + def take_systemdataset_samba4_snapshot(self): + basename = self.middleware.call_sync('systemdataset.config')['basename'] + if basename is None: + self.logger.warning('System dataset is not available, not taking snapshot') + return + + dataset = f'{basename}/samba4' + + proc = subprocess.run(['zfs', 'list', '-t', 'snapshot', '-H', '-o', 'name', '-s', 'name', '-d', '1', dataset], + stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf8', errors='ignore') + if proc.returncode != 0: + self.logger.warning('Unable to list dataset %s snapshots: %s', dataset, proc.stderr) + return + + snapshots = [s.split('@')[1] for s in proc.stdout.strip().split()] + for snapshot in [s for s in snapshots if s.startswith('update-')][:-4]: + self.logger.info('Deleting dataset %s snapshot %s', dataset, snapshot) + subprocess.run(['zfs', 'destroy', f'{dataset}@{snapshot}']) + + subprocess.run(['zfs', 'snapshot', f'{dataset}@update-{datetime.utcnow().strftime("%Y-%m-%d-%H-%M")}']) From a3ef71e5740b2697977c4baccada543bca9a416f Mon Sep 17 00:00:00 2001 From: themylogin Date: Thu, 2 May 2019 18:55:33 +0200 Subject: [PATCH 2/5] Fix compare_trains --- src/middlewared/middlewared/plugins/update.py | 11 ++++++----- .../middlewared/pytest/unit/plugins/test_update.py | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/middlewared/middlewared/plugins/update.py b/src/middlewared/middlewared/plugins/update.py index c1532ffd7f78..6dc29fea436b 100644 --- a/src/middlewared/middlewared/plugins/update.py +++ b/src/middlewared/middlewared/plugins/update.py @@ -73,11 +73,12 @@ def compare_trains(t1, t2): ): return CompareTrainsResult.MINOR_UPGRADE - if ( - isinstance(v1[1], int) and isinstance(v2[1], int) and v1[1] > v2[1] or - not isinstance(v2[1], int) and v1[1] > 0 - ): - return CompareTrainsResult.MINOR_DOWNGRADE + if isinstance(v1[1], int): + if ( + isinstance(v2[1], int) and v1[1] > v2[1] or + not isinstance(v2[1], int) and v1[1] > 0 + ): + return CompareTrainsResult.MINOR_DOWNGRADE class CheckUpdateHandler(object): diff --git a/src/middlewared/middlewared/pytest/unit/plugins/test_update.py b/src/middlewared/middlewared/pytest/unit/plugins/test_update.py index 161ed5e7ccd6..95c7b3635dc0 100644 --- a/src/middlewared/middlewared/pytest/unit/plugins/test_update.py +++ b/src/middlewared/middlewared/pytest/unit/plugins/test_update.py @@ -20,6 +20,7 @@ ("FreeNAS-11.2-STABLE", "FreeNAS-11-STABLE", CompareTrainsResult.MINOR_DOWNGRADE), ("FreeNAS-9.10-STABLE", "FreeNAS-9.10-STABLE", None), + ("FreeNAS-11-Nightlies", "FreeNAS-11-Nightlies", None), ]) def test__compare_trains(t1, t2, result): assert compare_trains(t1, t2) == result From 0124fd92e6fa9108be4539b99225709b612bfc1b Mon Sep 17 00:00:00 2001 From: themylogin Date: Thu, 2 May 2019 18:55:58 +0200 Subject: [PATCH 3/5] Put update version in samba4 dataset snapshot name --- src/middlewared/middlewared/plugins/update.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/middlewared/middlewared/plugins/update.py b/src/middlewared/middlewared/plugins/update.py index 6dc29fea436b..11e8d1b7749b 100644 --- a/src/middlewared/middlewared/plugins/update.py +++ b/src/middlewared/middlewared/plugins/update.py @@ -465,7 +465,7 @@ async def update(self, job, attrs=None): await self.middleware.call('failover.status') != 'BACKUP' ) ): - await self.middleware.call('update.take_systemdataset_samba4_snapshot') + await self.middleware.call('update.take_systemdataset_samba4_snapshot', new_manifest.Version()) if attrs.get('reboot'): await self.middleware.call('system.reboot', {'delay': 10}) @@ -658,7 +658,7 @@ def destroy_upload_location(self): raise CallError(f'Could not destroy memory device: {cp.stderr}') @private - def take_systemdataset_samba4_snapshot(self): + def take_systemdataset_samba4_snapshot(self, new_version): basename = self.middleware.call_sync('systemdataset.config')['basename'] if basename is None: self.logger.warning('System dataset is not available, not taking snapshot') @@ -677,4 +677,7 @@ def take_systemdataset_samba4_snapshot(self): self.logger.info('Deleting dataset %s snapshot %s', dataset, snapshot) subprocess.run(['zfs', 'destroy', f'{dataset}@{snapshot}']) - subprocess.run(['zfs', 'snapshot', f'{dataset}@update-{datetime.utcnow().strftime("%Y-%m-%d-%H-%M")}']) + current_version = "-".join(self.middleware.call_sync("system.info")["version"].split("-")[1:]) + new_version = "-".join(new_version.split("-")[1:]) + snapshot = f'update--{datetime.utcnow().strftime("%Y-%m-%d-%H-%M")}--{current_version}--{new_version}' + subprocess.run(['zfs', 'snapshot', f'{dataset}@{snapshot}']) From b4612cf3582f61e82fec5968808215bb24c7fe13 Mon Sep 17 00:00:00 2001 From: themylogin Date: Thu, 2 May 2019 18:56:12 +0200 Subject: [PATCH 4/5] Prettify task seems blocked message --- src/middlewared/middlewared/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/middlewared/middlewared/main.py b/src/middlewared/middlewared/main.py index 1912e0e18d17..95f27ca6db8a 100644 --- a/src/middlewared/middlewared/main.py +++ b/src/middlewared/middlewared/main.py @@ -1262,7 +1262,7 @@ def _loop_monitor_thread(self): if last == current: frame = sys._current_frames()[self.__thread_id] stack = traceback.format_stack(frame, limit=-10) - self.logger.warn(''.join(['Task seems blocked:'] + stack)) + self.logger.warn(''.join(['Task seems blocked:\n'] + stack)) last = current def run(self): From ea369f68ceb325997d8c372008e4f186383da630 Mon Sep 17 00:00:00 2001 From: themylogin Date: Thu, 2 May 2019 19:18:01 +0200 Subject: [PATCH 5/5] No need for new_version in samba4 dataset snapshot name --- src/middlewared/middlewared/plugins/update.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/middlewared/middlewared/plugins/update.py b/src/middlewared/middlewared/plugins/update.py index 11e8d1b7749b..0f82fe31538d 100644 --- a/src/middlewared/middlewared/plugins/update.py +++ b/src/middlewared/middlewared/plugins/update.py @@ -465,7 +465,7 @@ async def update(self, job, attrs=None): await self.middleware.call('failover.status') != 'BACKUP' ) ): - await self.middleware.call('update.take_systemdataset_samba4_snapshot', new_manifest.Version()) + await self.middleware.call('update.take_systemdataset_samba4_snapshot') if attrs.get('reboot'): await self.middleware.call('system.reboot', {'delay': 10}) @@ -658,7 +658,7 @@ def destroy_upload_location(self): raise CallError(f'Could not destroy memory device: {cp.stderr}') @private - def take_systemdataset_samba4_snapshot(self, new_version): + def take_systemdataset_samba4_snapshot(self): basename = self.middleware.call_sync('systemdataset.config')['basename'] if basename is None: self.logger.warning('System dataset is not available, not taking snapshot') @@ -673,11 +673,10 @@ def take_systemdataset_samba4_snapshot(self, new_version): return snapshots = [s.split('@')[1] for s in proc.stdout.strip().split()] - for snapshot in [s for s in snapshots if s.startswith('update-')][:-4]: + for snapshot in [s for s in snapshots if s.startswith('update--')][:-4]: self.logger.info('Deleting dataset %s snapshot %s', dataset, snapshot) subprocess.run(['zfs', 'destroy', f'{dataset}@{snapshot}']) current_version = "-".join(self.middleware.call_sync("system.info")["version"].split("-")[1:]) - new_version = "-".join(new_version.split("-")[1:]) - snapshot = f'update--{datetime.utcnow().strftime("%Y-%m-%d-%H-%M")}--{current_version}--{new_version}' + snapshot = f'update--{datetime.utcnow().strftime("%Y-%m-%d-%H-%M")}--{current_version}' subprocess.run(['zfs', 'snapshot', f'{dataset}@{snapshot}'])