Support for /v1/events

Search for events or get a particular event.

Change-Id: I8f27d8651b3186f53b337239039ffe729493e9ef
This commit is contained in:
Sandy Walsh 2015-03-04 09:24:34 -08:00
parent 9a71a249ee
commit ffc736c302
4 changed files with 135 additions and 7 deletions

View File

@ -71,7 +71,7 @@ def _get_api(config_location=None):
# but they could be deprecated and dropped.
# Only the versions specified here define
# the currently supported StackTach.v3 API.
enabled_versions = [1, 2]
enabled_versions = [1] # [1, 2]
if config_location:
config = ConfigParser.ConfigParser()

View File

@ -33,7 +33,7 @@ def _convert_traits(dtraits):
return dict(x for x in tuples)
def _get_streams(impl, req, resp, count=False):
def _find_streams(impl, req, resp, count=False):
older_than = req.get_param('older_than')
younger_than = req.get_param('younger_than')
state = req.get_param('state')
@ -57,7 +57,7 @@ def _get_streams(impl, req, resp, count=False):
if younger_than:
younger_than = parser.parse(younger_than)
return impl.get_streams(count=count,
return impl.find_streams(count=count,
older_than=older_than,
younger_than=younger_than,
state=state,
@ -88,7 +88,7 @@ class StreamCollection(common.FalconBase):
# details - get full details on stream (including events &
# distriquishing traits)
def on_get(self, req, resp):
streams = _get_streams(self.impl, req, resp)
streams = _find_streams(self.impl, req, resp)
resp.body = jsonutil.dumps(streams)
@ -98,7 +98,7 @@ class StreamItem(common.FalconBase):
stream_id = stream_id.lower()
count = stream_id == 'count'
if count:
streams = _get_streams(self.impl, req, resp, count=count)
streams = _find_streams(self.impl, req, resp, count=count)
else:
streams = _get_stream(self.impl, req, resp, stream_id)
resp.body = jsonutil.dumps(streams)
@ -110,6 +110,59 @@ class StreamItem(common.FalconBase):
self.impl.reset_stream(stream_id)
class EventCollection(common.FalconBase):
# Retrieve events, independent of stream.
# GET - list stream with qualifiers
# Qualifiers:
# datetime are ISO-8601 format, UTC
# from_datetime - events with timestamp > from_datetime
# default: now - 1hr
# to_datetime - events with timestamp < to_datetime
# default: now
# event_name - events of event type
# traits - find traits with specific traits
# mark - marker for paged results
# limit - max number of events to return (default: 200)
def on_get(self, req, resp):
from_datetime = req.get_param('from_datetime')
to_datetime = req.get_param('to_datetime')
event_name = req.get_param('event_name')
traits = req.get_param('traits')
traits = _convert_traits(traits)
mark = req.get_param('mark')
limit = req.get_param('limit')
if limit:
try:
limit = int(limit)
except (ValueError, TypeError):
limit = DEFAULT_LIMIT
else:
limit = DEFAULT_LIMIT
if from_datetime:
from_datetime = parser.parse(from_datetime)
if to_datetime:
to_datetime = parser.parse(to_datetime)
events = self.impl.find_events(from_datetime=from_datetime,
to_datetime=to_datetime,
event_name=event_name,
traits=traits,
mark=mark, limit=limit)
resp.body = jsonutil.dumps(events)
class EventItem(common.FalconBase):
def on_get(self, req, resp, message_id):
message_id = message_id.lower()
event = self.impl.get_event(message_id)
resp.body = jsonutil.dumps([event])
class Schema(object):
def _v(self):
return "/v%d" % self.version
@ -122,9 +175,16 @@ class Schema(object):
self.stream_collection = StreamCollection(impl)
self.stream_item = StreamItem(impl)
self.event_collection = EventCollection(impl)
self.event_item = EventItem(impl)
# Can't have a /streams/{item} route *and* a
# /streams/foo route. Have to overload the StreamItem
# handler.
self.api.add_route('%s/streams/{stream_id}' % self._v(),
self.stream_item)
self.api.add_route('%s/streams' % self._v(), self.stream_collection)
self.api.add_route('%s/events/{message_id}' % self._v(), self.event_item)
self.api.add_route('%s/events' % self._v(), self.event_collection)

View File

@ -77,11 +77,54 @@ class Stream(object):
}
class Event(object):
def __init__(self, event_id, name, timestamp):
self.event_id = event_id
self.name = name
self.timestamp = timestamp
def to_dict(self):
trait_names = ["foo", "zoo", "zip", "zap", "blah", "bar"]
d = {}
for t in trait_names:
dtype = random.randrange(4)
if dtype == 0:
d[t] = random.randrange(1000, 2000)
elif dtype == 1:
d[t] = str(uuid.uuid4())
elif dtype == 2:
d[t] = {
"__type__": "timex.TimeRange",
"begin": str(datetime.datetime.utcnow()
- datetime.timedelta(minutes=random.randrange(500))),
"end": str(datetime.datetime.utcnow())
}
elif dtype == 3:
d[t] = {
"__type__": "datetime",
"datetime": str(datetime.datetime.utcnow()
- datetime.timedelta(minutes=random.randrange(500)))
}
d.update({
"timestamp": {
"__type__": "datetime",
"datetime": str(self.timestamp)
},
"id": self.event_id,
"event_name": self.name,
"message_id": str(uuid.uuid4()),
"_mark": "%x" % self.event_id,
})
return d
class Impl(object):
def __init__(self, config, scratchpad):
self.config = config
self.scratchpad = scratchpad
self.streams = None
self.events = None
def _make_streams(self):
if self.streams:
@ -119,7 +162,25 @@ class Impl(object):
return self.streams
def get_streams(self, **kwargs):
def _make_events(self):
if self.events:
return self.events
minutes_in_48_hrs = 60 * 48
event_names = ["thing.create", "thing.delete", "thing.modify",
"thing.search", "thing.validate", "thing.archive"]
self.events = []
for event_id in range(100):
name = random.choice(event_names)
now = (datetime.datetime.utcnow() - datetime.timedelta(
minutes=random.randrange(minutes_in_48_hrs)))
self.events.append(Event(event_id + 100, name, now))
return self.events
def find_streams(self, **kwargs):
"""kwargs may be:
count: True/False
older_than
@ -142,3 +203,10 @@ class Impl(object):
def reset_stream(self, stream_id):
pass
def find_events(self, **kwargs):
events = self._make_events()
return [event.to_dict() for event in events]
def get_event(self, message_id):
return self._make_events()[0].to_dict()

View File

@ -1,6 +1,6 @@
[metadata]
name = quincy
version = 0.1
version = 0.2
author = Dark Secret Software Inc.
author-email = admin@darksecretsoftware.com
summary = StackTach.v3 REST API (no implementation)