Skip to content

Commit

Permalink
lots of updates, still trying to stabilize the semantics of the CARP …
Browse files Browse the repository at this point in the history
…action-result-report
  • Loading branch information
ndenny committed Jan 4, 2025
1 parent fe7cd70 commit d41dc7c
Show file tree
Hide file tree
Showing 19 changed files with 502 additions and 775 deletions.
90 changes: 71 additions & 19 deletions lib/Bastion/CARP.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,24 @@
Bastion.CARP
Common Action-Result/Report Protocol
Basic concepts...
requests (instances of isRequest or subclasses) encapsulates details of the action requested.
receipts contain details of the action's execution
results encapsulate the request and the receipt
reports are results with some extra features for output for human readability
...
Of these concepts, the two most important are request and result.
Basic plan for using CARP in applications...
Within an action method...
1. generate request
2. create an object with details of the action's success or failure (a receipt)
3. use one of the request reporting methods to generate a response report (e.g. report = request.failed(log) )
4. return the report.
"""
import operator
import datetime
import uuid
import traceback

Expand Down Expand Up @@ -153,6 +169,19 @@ def toJDN(self, **kwargs):

return jdn

def succeeded(self, record = None, *args, **kwargs):
return Report.Success(self, record, *args, **kwargs)

def failed(self, record = None, *args, **kwargs):
return Report.Failed(self, record, *args, **kwargs)

def crashed(self, record = None, *args, **kwargs):
return Report.Crashed(self, record, *args, **kwargs)

def inconclusive(self, record = None, *args, **kwargs):
return Report.Inconclusive(self, record, *args, **kwargs)



class isResult:
def __init__(self, request, status, record, **kwargs):
Expand All @@ -176,6 +205,7 @@ def __init__(self, request, status, record, **kwargs):
self.context = { }
self.when = kwargs.get('when', datetime.datetime.now())

context = kwargs.get('context', None)
if context is not None:
self.context = context.copy()

Expand Down Expand Up @@ -219,9 +249,9 @@ def inconclusive(self):
return self.status.is_inconclusive


class Report(isResult):
class isReport(isResult):
def __init__(self, request, status, record = None, *args, **kwargs):
isReceipt.__init__(self, request, status, record, *args, **kwargs)
isResult.__init__(self, request, status, record, *args, **kwargs)
self._body = kwargs.get('report', None)

@property
Expand All @@ -233,10 +263,10 @@ def body(self):
def toMD(self):
"""
I answer a markdown representation of self.
Base class is naive and just returns an empty string.
Base class is naive and just the string representation of my record.
Override in subclasses for detailed output.
"""
return ""
return str(self.record)

def toJDN(self, **kwargs):
jdn = isReceipt.toJDN(self, **kwargs)
Expand All @@ -246,18 +276,24 @@ def toJDN(self, **kwargs):
def __str__(self):
return yaml.dump(self.toJDN(), default_flow_style = False, indent = 3, sort_keys = True)



class Report(isReport):
@classmethod
def Success(cls, request, record = None, *args, **kwargs):
return cls(request. ResultStatus.Ok, record, *args, **kwargs)

@classmethod
def Failed(cls, request, record = None, *args, **kwargs):
return cls(request, ResultStatus.Failed, record, *args, **kwargs)
if isinstance(record, Exception):
return ExceptionReport(request, ResultStatus.Failed, record, *args, **kwargs)
else:
return cls(request, ResultStatus.Failed, record, *args, **kwargs)

@classmethod
def Crashed(cls, request, record = None, *args, **kwargs):
if isinstance(record, Exception):
return ReportException(request, ResultStatus.Crashed, record, *args, **kwargs)
return ExceptionReport(request, ResultStatus.Crashed, record, *args, **kwargs)
else:
return cls(request, ResultStatus.Crashed, record, *args, **kwargs)

Expand All @@ -266,7 +302,7 @@ def Inconclusive(cls, request, record = None, *args, **kwargs):
return cls(request, ResultStatus.Inconclusive, record, *args, **kwargs)


class ReportException(Report):
class ExceptionReport(isReport):
def __init__(self, request, *args, **kwargs):
#-- Can be called as...
#-- ReportException(request, errobj), or...
Expand All @@ -275,7 +311,7 @@ def __init__(self, request, *args, **kwargs):
status = args[0]
errobj = args[1]
else:
status = ReplyStatus.Failed
status = ReplyStatus.Fault
errobj = args[0]

assert status.indicates_failure, "ReportException must be created with a reply status indicating failure"
Expand All @@ -287,15 +323,31 @@ def __init__(self, request, *args, **kwargs):



class Request(isRequest):
def succeeded(self, record = None, *args, **kwargs):
return Report.Success(self, record, *args, **kwargs)

def failed(self, record = None, *args, **kwargs):
return Report.Failed(self, record, *args, **kwargs)

def crashed(self, record = None, *args, **kwargs):
return Report.Crashed(self, record, *args, **kwargs)
class isReceipt:
"""
I am an abstract base class for receipts.
Mostly, I'm used for run-time type checking.
"""
def toJDN(self, **kwargs):
raise NotImplementedError("is subclass responsibility")


class isReceiptOfResults(isReceipt):
"""
I am a thin wrapper around a sequence of results.
I am mostly used to build a single "record" from a sequence of operations,
with each operation having its own report.
"""
def __init__(self, results):
self.results = [ ]
for result in results:
if isinstance(result, isResult):
self.results.append(result)
else:
raise ValueError("result must be an instance of Bastion.CARP.isResult")

def __iter__(self):
return iter(self.results)

def inconclusive(self, record = None, *args, **kwargs):
return Report.Inconclusive(self, record, *args, **kwargs)
def toJDN(self, **kwargs):
return [result.toJDN(**kwargs) for result in self.results]
11 changes: 4 additions & 7 deletions lib/Bastion/Chronology.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import string
import datetime
import logging
from .Common import *
from Bastion.Common import SECONDS

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -87,10 +87,9 @@ def __init__(self, whence, separator = None):
elif isinstance(whence, str):
if self.separator:
words = whence.split(self.separator)
if len(words) == 3:
yW = words[0]
dW = words[1]
qW = words[2]
if len(words) == 4:
wY = words[0]
wDMQ = ''.join(words[1:])
else:
raise Exception("Quantim:__init__ parse error for '{}'".format(whence))
else:
Expand Down Expand Up @@ -118,7 +117,6 @@ def __init__(self, whence, separator = None):
def __str__(self):
lsq = self.qM % 36
msq = self.qM // 36
xmap = list(string.digits + string.ascii_uppercase)
sY = "{:03d}".format(self.dY)
sM = "{:X}".format(self.dM)
sD = "{:02d}".format(self.dD)
Expand All @@ -137,7 +135,6 @@ def quaver(self):

lsq = self.qM % 36
msq = self.qM // 36
xmap = list(string.digits + string.ascii_uppercase)
sY = "{:03d}".format(self.dY)
sM = "{:X}".format(self.dM)
sD = "{:02d}".format(self.dD)
Expand Down
40 changes: 11 additions & 29 deletions lib/Bastion/Clerks/BFD.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,22 @@
import os
import pathlib
import subprocess
import operator
import datetime
import json
import socket
import logging
import getpass
import shutil
import tarfile
import logging

from Bastion.Common import Thing, Unknown
from Bastion.Model import isAsset, isClerk
from Bastion.Curator import Manifest, BLONDE, Snap
from Bastion.Utils import pax
from Bastion.Common import RDN
from Bastion.Model import ARK, isVault, isAsset, isClerk
from Bastion.Curator import Manifest, BLONDE


logger = logging.getLogger(__name__)

class Clerk(isClerk):
def __init__(self, vault, **kwargs):
def __init__(self, vault, root, **kwargs):
isClerk.__init__(self)
self.vault = vault

@property
def bfd(self):
return self.vault.bfd

@property
def bank(self):
return self.vault.bank
assert isinstance(vault, isVault), "vault must be an instance of Bastion.Model.isVault"
assert isinstance(root, pathlib.PosixPath), "root must be an instance of PosixPath"

@property
def scratch(self):
return self.vault.scratch
self.vault = vault
self.root = root

#-----------------------------------------
#-- BEGIN Bastion.Model.isClerk PROTOCOL |
Expand All @@ -49,7 +31,6 @@ def sites(self):
for entry in self.root.iterdir():
if entry.is_dir():
sites.append(entry.name)

return tuple(sorted(sites))

def zones(self, site):
Expand Down Expand Up @@ -84,11 +65,12 @@ def manifest(self, *args):
ark = None
if len(args) == 1:
arg = args[0]
if isinstance(arg, Bastion.Model.isAsset):
if isinstance(arg, isAsset):
ark = arg.ARK
else:
ark = arg
elif len(args) == 3:
site, zone, asset = args
ark = ARK(site, zone, asset)
else:
raise ValueError
Expand All @@ -99,7 +81,7 @@ def manifest(self, *args):
for item in cell.iterdir():
if not item.is_dir():
blondes.append( BLONDE.decode(item.stem) )
manifest = Bastion.Curator.Manifest(ark, blondes)
manifest = Manifest(ark, blondes)

return manifest
#↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
Expand Down
23 changes: 6 additions & 17 deletions lib/Bastion/Clerks/SFTP.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,8 @@
import os
import pathlib
import subprocess
import operator
import datetime
import json
import socket
import logging
import getpass
import shutil
import tarfile
import logging

from Bastion.Common import Thing, Unknown
from Bastion.Model import isAsset, isClerk
from Bastion.Curator import Manifest, BLONDE, Snap
from Bastion.Packers.TARs import pax
from Bastion.Common import RDN
from Bastion.Model import ARK, isAsset, isClerk
from Bastion.Curator import Manifest, BLONDE
from Bastion.NetOps.sCURL import SCURLer


Expand Down Expand Up @@ -75,11 +63,12 @@ def manifest(self, *args):
ark = None
if len(args) == 1:
arg = args[0]
if isinstance(arg, Bastion.Model.isAsset):
if isinstance(arg, isAsset):
ark = arg.ARK
else:
ark = arg
elif len(args) == 3:
site, zone, asset = args
ark = ARK(site, zone, asset)
else:
raise ValueError
Expand All @@ -90,7 +79,7 @@ def manifest(self, *args):
for alien in cell.lsall():
if not alien.is_dir():
blondes.append( BLONDE.decode(alien.stem) )
manifest = Bastion.Curator.Manifest(ark, blondes)
manifest = Manifest(ark, blondes)

return manifest
#↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
Expand Down
Loading

0 comments on commit d41dc7c

Please sign in to comment.