From 9fcbbffdc039d6ad10d92101171b6841f6fa7756 Mon Sep 17 00:00:00 2001 From: Nathan Denny Date: Tue, 1 Apr 2025 14:35:35 -0400 Subject: [PATCH] Mulligan! --- bin/bastion.py | 98 +++++++++++++++++--------------------- lib/Bastion/Clerks/SFTP.py | 10 ++-- lib/Bastion/Site.py | 2 + 3 files changed, 49 insertions(+), 61 deletions(-) diff --git a/bin/bastion.py b/bin/bastion.py index 52e3fc3..b57c640 100755 --- a/bin/bastion.py +++ b/bin/bastion.py @@ -22,12 +22,12 @@ sys.path.insert(0, str(LIB_PATH)) -from Bastion.Common import Boggle, asPath, toJDN +from Bastion.Common import Boggle, asPath, toJDN from Bastion.Chronology import Quantim from Bastion.Site import Site from Bastion.Condo import Condex -from Bastion.Model import ARK, isAsset -from Bastion.CARP import Request, isResult, isReport, BagReceipt +from Bastion.Model import ARK +from Bastion.CARP import Request, isResult, isReport import Bastion.Vaults.HPSS import Bastion.Vaults.BFD import Bastion.Vaults.SFTP @@ -119,31 +119,18 @@ def site(self, s): def asset(self, ark): return self.site(ark.site).asset(ark) - def vault(self, which, site = None): + def vault(self, name, site = None): """ I answer an instance of a storage vault given a name and optional site. - .vault(name:str) - .vault(asset:isAsset) - .vault(ark:ARK) """ - if isinstance(which, str): - name = which - if ((name[0] == '{') and (name[-1] == '}')): - name = name[1:-1] - if name in self.conf['vaults']: - protocol = self.conf['vaults'][name]['protocol'] - cls = Bastion.Model.Vault.handling(protocol) - return cls(name).configured(self.conf) - - if isinstance(which, isAsset): - asset = which - return self.vault(asset.policy.vault) - - if isinstance(which, ARK): - asset = self.asset(which) - return self.vault(asset.policy.vault) - - return None + if ((name[0] == '{') and (name[-1] == '}')): + name = name[1:-1] + if name in self.conf['vaults']: + protocol = self.conf['vaults'][name]['protocol'] + cls = Bastion.Model.Vault.handling(protocol) + return cls(name).configured(self.conf) + else: + return None @property def sites(self): @@ -259,25 +246,25 @@ def run(self): else: sys.exit(1) - def remember(self, result): + def remember(self, answer): """ Given an answer structure and opts (as a dict), I serialize the answer to YAML and save the answer as a file in the logs. I need answer to include "log.scope" in the context block. If no "log.scope" is declared, I silently ignore the request to record. """ - if 'log.scope' in result.request.context: + if 'log.scope' in answer.request.context: #-- only write a log file if we have an explicit log.scope in the answer's context block. - session = result.request.ID + session = answer.request.ID scope = self.logroot - if result.request.context['log.scope'] != '*': - scope = scope / result.request.context['log.scope'] + if answer.request.context['log.scope'] != '*': + scope = scope / answer.request.context['log.scope'] halo = scope / "{}.yaml".format(session) halo.parent.mkdir(parents = True, exist_ok = True) with open(halo, 'wt') as fout: - self.emit_YAML(toJDN(result), fout) + self.emit_YAML(answer.toJDN(), fout) def emit(self, answer, ostream = None): ostream = ostream if (ostream is not None) else sys.stdout @@ -300,7 +287,6 @@ def emit_JSON(self, result, ostream): def emit_PROSE(self, result, ostream): request = result.request - ostream.write("ID: {}\n".format(request.ID)) ostream.write("request: {}\n".format(request.lede)) ostream.write("reply: {reply.code} {reply.gloss}\n".format(reply=result.status)) ostream.write("# {reply.lede}\n".format(reply=result)) @@ -359,7 +345,7 @@ def do_bank_asset(self, request): request['log.scope'] = "site/{}".format(ark.site) result = vault.push(asset, client = self.hostname) - if result.succeeded: + if result.indicates_success: return request.succeeded(result, report = "pushed full backup of {} to {}".format(str(ark), str(result.blonde))) else: return request.failed(result, report = "while pushing full backup of {}, something went wrong!".format(str(ark))) @@ -399,7 +385,7 @@ def do_bank_zone(self, request): site = self.site(ark) zone = site.zone(ark) - arks = [asset.ARK for asset in zone] + arks = [asset.ark for asset in zone] request['log.scope'] = "site/{}".format(site.name) return self._bank_assets(request, arks) @@ -415,17 +401,18 @@ def _bank_assets(self, request, arks): """ helper method to push (bank) many assets given a single (batched) request. """ - results = BagReceipt() + results = [ ] for ark in arks: asset = self.asset(ark) - vault = self.vault(asset) + vault = self.vault(asset.policy.vault) result = vault.push(asset, client = self.hostname) results.append(result) - all_succeeded = all([result.succeeded for result in results]) - all_failed = all([result.failed for result in results]) + all_succeeded = all([result.indicates_success for result in results]) + all_failed = all([result.indicates_failure for result in results]) + + pushed = [result['blonde'] for result in results if result.indicates_success] - pushed = [result.blonde for result in results if result.succeeded] if all_succeeded: return request.succeeded(results, report = "all {} assets successfully pushed".format(len(results))) elif all_failed: @@ -450,15 +437,14 @@ def do_amend_asset(self, request): site = self.site(ark) asset = site.asset(ark) vault = self.vault(asset.policy.vault) - result = vault.amend(asset) + action = vault.amend(asset) request['log.scope'] = "site/{}".format(ark.site) - if result.indicates_success: - blonde = result.body['blonde'] - return request.succeeded(result, report = "amended asset {} to {}".format(str(ark), str(blonde))) + if action.succeeded: + return request.succeeded(action, report = "amended asset {} to {}".format(str(ark), str(action.blonde))) else: - return request.failed(result, report = "amend operation on asset {} failed".format(str(ark))) + return request.failed(action, report = "amend operation on asset {} failed".format(str(ark))) def do_amend_site(self, request): """ @@ -495,7 +481,7 @@ def do_amend_zone(self, request): site = self.site(ark) zone = site.zone(ark) - arks = [asset.ARK for asset in zone] + arks = [asset.ark for asset in zone] request['log.scope'] = "site/{}".format(site.name) return self._amend_assets(request, arks) @@ -503,17 +489,17 @@ def _amend_assets(self, request, arks): """ helper method to amend (differential backup) many assets given a single (batched) request. """ - results = BagReceipt() + results = [ ] for ark in arks: asset = self.asset(ark) vault = self.vault(asset.policy.vault) result = vault.amend(asset, client = self.hostname) results.append(result) - all_succeeded = all([result.succeeded for result in results]) - all_failed = all([result.failed for result in results]) - - amended = [result.blonde for result in results if result.succeeded] + all_succeeded = all([result.indicates_success for result in results]) + all_failed = all([result.indicates_failure for result in results]) + + amended = [result['blonde'] for result in results if result.indicates_success] if all_succeeded: return request.succeeded(result, report = "all {} assets successfully amended".format(len(results))) @@ -670,10 +656,9 @@ def do_export_site_catalog(self, request): for asset_name in catalog[zone_name]: manifest = vault.manifest(ARK(site_name, zone_name, asset_name)) anchor = manifest.head.anchor - origin = manifest.head.earliest.isoformat() - recent = manifest.head.latest.isoformat() - #doclins.append("* {} {} ({} → {})".format(asset_name, str(anchor), origin, recent)) - doclins.append(" * {}".format(repr(manifest.head))) + origin = anchor.when.datetime.isoformat() + recent = manifest.head.tail.when.datetime.isoformat() + doclins.append("* {} {} ({} → {})".format(asset_name, str(anchor), origin, recent)) doc = '\n'.join(doclins) return request.succeeded(catalog, report = doc) @@ -700,6 +685,9 @@ def do_export_zones_provisioned(self, request): * lists all zones provisioned in the given vault for the named site """ vault = self.vault( request.args[0] ) + if not vault: + return request.failed(None, "no vault {} exists".format(vault)) + site_name = request.args[1] zone_names = vault.zones(site_name) @@ -823,7 +811,7 @@ def do_refresh_keytab(self, request): rusina = app.site('rusina') soundscapes = rusina.zone('soundscapes') asset = soundscapes['HackathonData'] - vault = app.vault(asset) + vault = app.vault(asset.policy.vault) else: app.run( ) diff --git a/lib/Bastion/Clerks/SFTP.py b/lib/Bastion/Clerks/SFTP.py index b24fbd9..1168bed 100644 --- a/lib/Bastion/Clerks/SFTP.py +++ b/lib/Bastion/Clerks/SFTP.py @@ -50,8 +50,9 @@ def assets(self, site, zone): assets = [ ] zroot = self.scurler / site / zone if zroot.exists( ): - for alien in zroot.is_dir(): - assets.append(alien.name) + for alien in zroot: + if alien.is_folder: + assets.append(alien.name) return tuple(sorted(assets)) def manifest(self, *args): @@ -75,12 +76,9 @@ def manifest(self, *args): blondes = [ ] cell = self.scurler / ark.site / ark.zone / ark.asset - print("CELL:", cell) - print(type(cell)) if cell.exists: for alien in cell.lsall(): - print("ALIEN: ", alien) - if not alien.is_dir(): + if not alien.is_folder: blondes.append( BLONDE.decode(alien.stem) ) manifest = Manifest(ark, blondes) diff --git a/lib/Bastion/Site.py b/lib/Bastion/Site.py index 37bc8c4..3d80106 100644 --- a/lib/Bastion/Site.py +++ b/lib/Bastion/Site.py @@ -34,6 +34,8 @@ def named(nm): def __new__(cls, site): if isinstance(site, cls): return site + elif isinstance(site, ARK): + return cls(site.site) else: if site in Site.SITES: return Site.SITES[site]