def addNewDelta(self, uploadContent, environ, **kwargs): """ Add new delta """ dbobj = getVal(self.dbI, **kwargs) hashNum = uploadContent['id'] if dbobj.get('deltas', search=[['uid', hashNum]], limit=1): # This needs to be supported as it can be re-initiated again. TODO msg = 'Something weird has happened... Check server logs; Same ID is already in DB' kwargs['http_respond'].ret_409('application/json', kwargs['start_response'], None) return getCustomOutMsg(errMsg=msg, errCode=409) tmpfd = NamedTemporaryFile(delete=False) tmpfd.close() self.getmodel(uploadContent['modelId'], **kwargs) outContent = { "ID": hashNum, "InsertTime": getUTCnow(), "UpdateTime": getUTCnow(), "Content": uploadContent, "State": "accepting", "modelId": uploadContent['modelId'] } self.siteDB.saveContent(tmpfd.name, outContent) out = self.policer[kwargs['sitename']].acceptDelta(tmpfd.name) outDict = { 'id': hashNum, 'lastModified': convertTSToDatetime(outContent['UpdateTime']), 'href': "%s/%s" % (environ['SCRIPT_URI'], hashNum), 'modelId': out['modelId'], 'state': out['State'], 'reduction': out['ParsedDelta']['reduction'], 'addition': out['ParsedDelta']['addition'] } print 'Delta was %s. Returning info %s' % (out['State'], outDict) if out['State'] in ['accepted']: kwargs['http_respond'].ret_201( 'application/json', kwargs['start_response'], [('Last-Modified', httpdate(out['UpdateTime'])), ('Location', outDict['href'])]) return outDict else: kwargs['http_respond'].ret_500('application/json', kwargs['start_response'], None) if 'Error' in out.keys(): errMsg = "" for key in ['errorNo', 'errorType', 'errMsg']: if key in out['Error'].keys(): errMsg += " %s: %s" % (key, out['Error'][key]) return getCustomOutMsg(errMsg=errMsg, exitCode=500)
def deltas_id(environ, **kwargs): """ API Call associated with specific delta Method: GET Output: application/json Examples: https://server-host/sitefe/v1/deltas/([-_A-Za-z0-9]+) # Will return info about specific delta """ # METHOD DELETE!!!!! TODO if environ['REQUEST_METHOD'].upper() == 'DELETE': kwargs['http_respond'].ret_405('application/json', kwargs['start_response'], ('Location', '/')) print('DELETE Method is not supported yet. Return 405') return [ getCustomOutMsg(errMsg="Method %s is not supported in %s" % environ['REQUEST_METHOD'].upper(), errCode=405) ] modTime = getModTime(kwargs['headers']) print('Delta Status query for %s' % kwargs['mReg'][0]) delta = DELTABACKEND.getdelta(kwargs['mReg'][0], **kwargs) if not delta: kwargs['http_respond'].ret_204( 'application/json', kwargs['start_response'], [('Last-Modified', httpdate(getUTCnow()))]) print('Return empty list. There are no deltas on the system') return [] if modTime > delta['updatedate']: print( 'Delta with ID %s was not updated so far. Time request comparison requested' % kwargs['mReg'][0]) kwargs['http_respond'].ret_304( 'application/json', kwargs['start_response'], ('Last-Modified', httpdate(delta['updatedate']))) return [] if kwargs['urlParams']['oldview']: kwargs['http_respond'].ret_200( 'application/json', kwargs['start_response'], [('Last-Modified', httpdate(delta['updatedate']))]) return [delta] current = {} current = { "id": delta['uid'], "lastModified": convertTSToDatetime(delta['updatedate']), "state": delta['state'], "href": "%s" % environ['SCRIPT_URI'], "modelId": delta['modelid'] } if not kwargs['urlParams']['summary']: current['addition'] = encodebase64(delta['addition'], kwargs['urlParams']['encode']) current['reduction'] = encodebase64(delta['reduction'], kwargs['urlParams']['encode']) print('Returning delta %s information. Few details: ModelID: %s, State: %s, LastModified: %s' % \ (current["id"], current["modelId"], current["state"], current["lastModified"])) kwargs['http_respond'].ret_200( 'application/json', kwargs['start_response'], [('Last-Modified', httpdate(delta['updatedate']))]) return [current]
def internallCall(caller, environ, **kwargs): """ Delta internal call which catches all exception """ returnDict = {} exception = "" try: return caller(environ, **kwargs) except (ModelNotFound, DeltaNotFound) as ex: exception = '%s: Received Exception: %s' % (caller, ex) kwargs['http_respond'].ret_404('application/json', kwargs['start_response'], None) returnDict = getCustomOutMsg(errMsg=ex.__str__(), errCode=404) except (ValueError, BadRequestError, IOError) as ex: exception = '%s: Received Exception: %s' % (caller, ex) kwargs['http_respond'].ret_500('application/json', kwargs['start_response'], None) returnDict = getCustomOutMsg(errMsg=ex.__str__(), errCode=500) if exception: print exception return returnDict
def commitdelta(self, deltaID, newState='UNKNOWN', internal=False, hostname=None, **kwargs): """Change delta state.""" dbobj = getVal(self.dbI, **kwargs) if internal: out = dbobj.get('hoststates', search=[['deltaid', deltaID], ['hostname', hostname]]) if not out: msg = 'This query did not returned any host states for %s %s' % ( deltaID, hostname) raise WrongDeltaStatusTransition(msg) self.stateM._stateChangerHost( dbobj, out[0]['id'], **{ 'deltaid': deltaID, 'state': newState, 'insertdate': getUTCnow(), 'hostname': hostname }) if newState == 'remove': # Remove state comes only from modify and by agent itself self.stateM.stateChange(dbobj, { 'uid': deltaID, 'state': newState }) return getCustomOutMsg(msg='Internal State change approved', exitCode=200) delta = self.getdelta(deltaID, **kwargs) print('Commit Action for delta %s' % delta) # Now we go directly to commited in case of commit if delta['state'] != 'accepted': msg = "Delta state in the system is not in accepted state. \ State on the system: %s. Not allowed to change." % delta[ 'state'] print(msg) raise WrongDeltaStatusTransition(msg) self.stateM.commit(dbobj, {'uid': deltaID, 'state': 'committing'}) return {'status': 'OK'}
def deltas(environ, **kwargs): """ API Call associated with deltas Method: GET Output: application/json Examples: https://server-host/sitefe/v1/deltas/ # Will return info about all deltas Method: POST Output: application/json Examples: https://server-host/sitefe/v1/deltas/ # Will add new delta and returns it's ID """ # ====================================================== # GET if environ['REQUEST_METHOD'].upper() == 'GET': modTime = getModTime(kwargs['headers']) outdeltas = DELTABACKEND.getdelta(None, **kwargs) if kwargs['urlParams']['oldview']: print 'Return All deltas. 200 OK' kwargs['http_respond'].ret_200('application/json', kwargs['start_response'], None) return outdeltas outM = {"deltas": []} if not outdeltas: kwargs['http_respond'].ret_204( 'application/json', kwargs['start_response'], [('Last-Modified', httpdate(getUTCnow()))]) print 'Return empty list. There are no deltas on the system' return [] updateTimestamp = 0 for delta in outdeltas: if modTime > delta['updatedate']: continue updateTimestamp = updateTimestamp if updateTimestamp > delta[ 'updatedate'] else delta['updatedate'] current = { "id": delta['uid'], "lastModified": convertTSToDatetime(delta['updatedate']), "state": delta['state'], "href": "%s/%s" % (environ['SCRIPT_URI'], delta['uid']), "modelId": delta['modelid'] } if not kwargs['urlParams']['summary']: # Doing here not encode, because we are decoding. So it is opposite. current["addition"] = decodebase64( delta['addition'], not kwargs['urlParams']['encode']) current["reduction"] = decodebase64( delta['reduction'], not kwargs['urlParams']['encode']) outM["deltas"].append(current) if not outM["deltas"]: kwargs['http_respond'].ret_304( 'application/json', kwargs['start_response'], ('Last-Modified', httpdate(modTime))) return [] kwargs['http_respond'].ret_200( 'application/json', kwargs['start_response'], [('Last-Modified', httpdate(updateTimestamp))]) print 'Return Last Delta. 200 OK' return outM["deltas"] # ====================================================== # POST out = {} postRequest = False if environ['REQUEST_METHOD'].upper() == 'POST': postRequest = is_post_request(environ) if not postRequest: if is_application_json(environ): out = get_json_post_form(environ) else: kwargs['http_respond'].ret_400('application/json', kwargs['start_response'], None) customErr = getCustomOutMsg( errMsg= 'You did POST method, but provided CONTENT_TYPE is not correct', errCode=400) print 'Return 400. More details: %s' % customErr return customErr if not out: out = get_post_form(environ) newDelta = {} for key in out.keys(): newDelta[key] = out.get(key, "") for key in ['modelId', 'id']: if not newDelta[key]: customErr = getCustomOutMsg( errMsg='You did POST method, %s is not specified' % key, errCode=400) print 'Wrong delta: %s. Parsed:%s Error: %s' % (out, newDelta, customErr) kwargs['http_respond'].ret_400('application/json', kwargs['start_response'], None) return customErr if not newDelta['reduction'] and not newDelta['addition']: customErr = getCustomOutMsg( errMsg= 'You did POST method, but nor reduction, nor addition is present', errCode=400) print 'Wrong delta: %s. Parsed:%s Error: %s' % (out, newDelta, customErr) kwargs['http_respond'].ret_400('application/json', kwargs['start_response'], None) return customErr return DELTABACKEND.addNewDelta(newDelta, environ, **kwargs)
def models(environ, **kwargs): """ Returns a collection of available model resources within the Resource Manager Method: GET Output: application/json Examples: https://server-host/sitefe/v1/models/ # Returns list of all models; """ # Get IF_MODIFIED_SINCE modification time in timestamp modTime = getModTime(kwargs['headers']) outmodels = DELTABACKEND.getmodel(**kwargs) if not outmodels: kwargs['http_respond'].ret_500('application/json', kwargs['start_response'], None) print 'LastModel does not exist in dictionary. First time run? See documentation' return getCustomOutMsg(errMsg="No models are available...", errCode=500) outmodels = [outmodels] if isinstance(outmodels, dict) else outmodels outM = {"models": []} current = { "id": outmodels[0]['uid'], "creationTime": convertTSToDatetime(outmodels[0]['insertdate']), "href": "%s/%s" % (environ['SCRIPT_URI'], outmodels[0]['uid']) } print outmodels[0]['insertdate'], modTime, getUTCnow() if outmodels[0]['insertdate'] < modTime: print '%s and %s' % (outmodels[0]['insertdate'], modTime) kwargs['http_respond'].ret_304( 'application/json', kwargs['start_response'], ('Last-Modified', httpdate(outmodels[0]['insertdate']))) return [] kwargs['http_respond'].ret_200( 'application/json', kwargs['start_response'], [('Last-Modified', httpdate(outmodels[0]['insertdate']))]) if kwargs['urlParams']['oldview']: print 'Requested oldview model output. Return 200' return outmodels elif kwargs['urlParams']['current']: if not kwargs['urlParams']['summary']: current['model'] = encodebase64( DELTABACKEND.getmodel(outmodels[0]['uid'], content=True, **kwargs), kwargs['urlParams']['encode']) outM['models'].append(current) print 'Requested only current model. Return 200. Last Model %s' % outmodels[ 0]['uid'] return [current] elif not kwargs['urlParams']['current']: for model in outmodels: tmpDict = { "id": model['uid'], "creationTime": convertTSToDatetime(model['insertdate']), "href": "%s/%s" % (environ['SCRIPT_URI'], model['uid']) } if not kwargs['urlParams']['summary']: tmpDict['model'] = encodebase64( DELTABACKEND.getmodel(model['uid'], content=True, **kwargs), kwargs['urlParams']['encode']) outM['models'].append(tmpDict) print 'Returning all models known to the system. Return 200' return outM['models']
def application(environ, start_response): """ Main start. WSGI will always call this function, which will check if call is allowed. """ # HTTP responses var check_initialized(environ) global _SITES try: environ['CERTINFO'] = _CERTHANDLER.getCertInfo(environ) _CERTHANDLER.validateCertificate(environ) except Exception as ex: _HTTPRESPONDER.ret_401('application/json', start_response, None) return [json.dumps(getCustomOutMsg(errMsg=ex.__str__(), errCode=401))] path = environ.get('PATH_INFO', '').lstrip('/') sitename = environ.get('REQUEST_URI', '').split('/')[1] if sitename not in _SITES: _HTTPRESPONDER.ret_404('application/json', start_response, None) return [ json.dumps( getCustomOutMsg( errMsg="Sitename %s is not configured. Contact Support." % sitename, errCode=404)) ] for regex, callback, methods, params, acceptheader in URLS: match = regex.match(path) if match: regMatch = get_match_regex(environ, regex) if environ['REQUEST_METHOD'].upper() not in methods: _HTTPRESPONDER.ret_405('application/json', start_response, [('Location', '/')]) return [ json.dumps( getCustomOutMsg( errMsg="Method %s is not supported in %s" % (environ['REQUEST_METHOD'].upper(), callback), errCode=405)) ] environ['jobview.url_args'] = match.groups() try: headers = getHeaders(environ) # by default only 'application/json' is accepted. It can be overwritten for each API inside # definition of URLs or headers are passed to the API call and can be checked there. # Preference is to keep them inside URL definitions. if 'ACCEPT' not in headers: headers['ACCEPT'] = 'application/json' if acceptheader: if headers['ACCEPT'] not in acceptheader: _HTTPRESPONDER.ret_406('application/json', start_response, None) return [ json.dumps( getCustomOutMsg( errMsg= "Not Acceptable Header. Provided: %s, Acceptable: %s" % (headers['ACCEPT'], acceptheader), errCode=406)) ] out = internallCall(caller=callback, environ=environ, start_response=start_response, mReg=regMatch, http_respond=_HTTPRESPONDER, urlParams=getUrlParams(environ, params), headers=headers, sitename=sitename) return returnBasedOnHeaders(out, headers) except (NotSupportedArgument, TooManyArgumentalValues) as ex: print 'Send 400 error. More details: %s' % json.dumps( getCustomOutMsg(errMsg=ex.__str__(), errCode=400)) _HTTPRESPONDER.ret_400('application/json', start_response, None) return [ json.dumps( getCustomOutMsg(errMsg=ex.__str__(), errCode=400)) ] except Exception as ex: print 'Send 500 error. More details: %s' % json.dumps( getCustomOutMsg(errMsg=ex.__str__(), errCode=500)) _HTTPRESPONDER.ret_500('application/json', start_response, None) return [ json.dumps( getCustomOutMsg(errMsg=ex.__str__(), errCode=500)) ] errMsg = "Such API does not exist. Not Implemented" print 'Send 501 error. More details: %s' % json.dumps( getCustomOutMsg(errMsg=errMsg, errCode=501)) _HTTPRESPONDER.ret_501('application/json', start_response, [('Location', '/')]) return [json.dumps(getCustomOutMsg(errMsg=errMsg, errCode=501))]
def application(environ, start_response): """ Main start. WSGI will always call this function, which will check if call is allowed. """ # HTTP responses var _HTTP_RESPOND = HTTPResponses() check_initialized(environ) certHandler = CertHandler() permissions = {} print 'Environment information: %s ' % environ try: environ['CERTINFO'] = certHandler.getCertInfo(environ) permissions = certHandler.validateCertificate(environ) except Exception as ex: _HTTP_RESPOND.ret_401('application/json', start_response, None) return [json.dumps(getCustomOutMsg(errMsg=ex.__str__(), errCode=401))] path = environ.get('PATH_INFO', '').lstrip('/') sitename = environ.get( 'REQUEST_URI', '').split('/')[1] # TODO. DO Check for SiteName in conf for regex, callback, methods, params, acceptheader in URLS: match = regex.match(path) if match: regMatch = get_match_regex(environ, regex) if environ['REQUEST_METHOD'].upper() not in methods: _HTTP_RESPOND.ret_405('application/json', start_response, [('Location', '/')]) return [ json.dumps( getCustomOutMsg( errMsg="Method %s is not supported in %s" % (environ['REQUEST_METHOD'].upper(), callback), errCode=405)) ] environ['jobview.url_args'] = match.groups() try: headers = getHeaders(environ) # by default only 'application/json' is accepted. It can be overwritten for each API inside # definition of URLs or headers are passed to the API call and can be checked there. # Preference is to keep them inside URL definitions. if 'ACCEPT' not in headers: headers['ACCEPT'] = 'application/json' # Even it is not specified, we work only with application/json. # Any others have option to overwrite it. if acceptheader: if headers['ACCEPT'] not in acceptheader: _HTTP_RESPOND.ret_406('application/json', start_response, None) return [ json.dumps( getCustomOutMsg( errMsg= "Not Acceptable Header. Provided: %s, Acceptable: %s" % (headers['ACCEPT'], acceptheader), errCode=406)) ] # TODO. Find better way for browser check # elif headers['ACCEPT'] != 'application/json': # _HTTP_RESPOND.ret_406('application/json', start_response, None) # return [json.dumps(getCustomOutMsg(errMsg="Header was not accepted. Provided: %s, Acceptable: %s" % (headers['ACCEPT'], 'application/json'), errCode=406))] return [ json.dumps( internallCall(caller=callback, environ=environ, start_response=start_response, mReg=regMatch, http_respond=_HTTP_RESPOND, urlParams=getUrlParams(environ, params), headers=headers, sitename=sitename)) ] except (NotSupportedArgument, TooManyArgumentalValues) as ex: print 'Send 400 error. More details: %s' % json.dumps( getCustomOutMsg(errMsg=ex.__str__(), errCode=400)) _HTTP_RESPOND.ret_400('application/json', start_response, None) return [ json.dumps( getCustomOutMsg(errMsg=ex.__str__(), errCode=400)) ] print 'Send 501 error. More details: %s' % json.dumps( getCustomOutMsg(errMsg="Such API does not exist. Not Implemented", errCode=501)) _HTTP_RESPOND.ret_501('application/json', start_response, [('Location', '/')]) return [ json.dumps( getCustomOutMsg(errMsg="Such API does not exist. Not Implemented", errCode=501)) ]