diff --git a/lib/Bastion/CARP.py b/lib/Bastion/CARP.py index 826541f..0b1754b 100644 --- a/lib/Bastion/CARP.py +++ b/lib/Bastion/CARP.py @@ -3,6 +3,9 @@ Common Action-Result/Report Protocol """ +import uuid + + class ReplyStatus(tuple): DEFAULT_CATEGORY_GLOSS = { '1': 'FYI', @@ -29,6 +32,7 @@ class ReplyStatus(tuple): 412: "precondition failed", 416: "range not satisfiable", 500: "exception", + 599: "crash and burn" } def __new__(cls, *args): @@ -100,72 +104,98 @@ def is_inconclusive(self): ReplyStatus.RangeError = ReplyStatus(416) ReplyStatus.Exception = ReplyStatus(500) ReplyStatus.Fault = ReplyStatus.Exception -ReplyStatus.Crashed = ReplyStatus(500) +ReplyStatus.Crashed = ReplyStatus(599) ResultStatus = ReplyStatus #-- Alias for ReplyStatus -class isAction: - def __init__(self): - self.request = None - self.result = None - self.log = [ ] - - def __call__(self, *args, **kwargs): - self.request = Request(self.name, args, kwargs) - self.do(*args, **kwargs) - return self.result() - - def debug(self, msg): - pass - - def info(self, msg): - pass - - def warn(self, msg): - pass - - def error(self, msg): - pass - - def critical(self, msg): - pass - - -class isHpssAction(isAction): - def __init__(self, vault): - isAction.__init__(self) - self.vault = vault - - -class PushAction(isHpssAction): - def do(self, *args, **kwargs): - self.critical("action is not yet implemented") - self.fail("not implemented, yet!") - - - -fortress.push("[@alfisol:oobabooga/models]") +class isReceipt: + def __init__(self, request, status, brief, obj, context = None, **kwargs): + #-- request is a 2-tuple of (action, [arg1, ...]) + #-- status is an instance of ReplyStatus + #-- brief is an arbitrary (assumed human readable) text string + #-- obj is any JSON serializable object. + #-- context, if given, is a dict of extra key-value associations. + if not isinstance(status, ReplyStatus): + raise ValueError("status must be of type ReplyStatus") + + self.RID = kwargs.get('ID', str(uuid.uuid4())) + self.action = request[0] + self.args = request[1] + self.status = status + self.brief = str(msg) + self.body = obj + self.context = { } + + if context is not None: + self.context = context.copy() + + def toJDN(self, **kwargs): + #-- receipts have FOUR top level sections: request, result, context, and data. + #-- result is the http-like status code and message, e.g. (200, "Ok") + #-- brief is a single text string that is a human readable summary of the receipt. + #-- context is an arbitrary set of key-value pairs + #-- data is a JSON serializable object that is the body of the receipt. + if callable(getattr(obj, 'toJDN', None)): + payload = obj.toJDN() + else: + payload = obj + + jdn = { } + + jdn['request'] = { + 'ID': self.RID, + 'action': self.action, + 'args': list(self.args), + 'context': self.context.copy(), + } + jdn['request']['result'] = { + 'status': self.status.code, + 'message': self.status.gloss, + 'summary': self.brief, + } + jdn['request']['result']['body'] = { + 'data': payload + } + return jdn + @property + def succeeded(self): + return self.status.indicates_success + @property + def failed(self): + return self.status.indicates_failure + @property + def inconclusive(self): + return self.status.is_inconclusive -fortress.push = HPSSPushAction(fortress) -fortress.push(models) +class Receipt(isReceipt): + pass -class PushRequest(isRequest): - def __init__(self): - pass +class Report(isReceipt): + def __init__(self, status, brief, doc, obj = None, **kwargs): + isReceipt.__init__(self, status, brief, obj, **kwargs) + self.report = doc + def toJDN(self, **kwargs): + jdn = isReceipt.toJDN(self, **kwargs) + jdn['request']['result']['report'] = str(self.report) + return jdn -class PushAction(isAction): - def __init__(self, vault): - self.vault = vault - def do(self, *args, **kwargs): - return self.crashed("not implemented, yet!") +def SUCCEEDED(doc, obj = None, **kwargs): + return Report(ReplyStatus.Ok, doc, obj, **kwargs) +def FAILED(doc, obj = None, **kwargs): + return CARP(ReplyStatus.Failed, doc, obj, **kwargs) +def CRASHED(doc, obj = None, **kwargs): + return CARP(ReplyStatus.Crashed, doc, obj, **kwargs) +SUCCESS = SUCCEEDED +FAILURE = FAILED +CRASH = CRASHED