diff --git a/quincy/api.py b/quincy/api.py index 717e8ce..3cdb008 100644 --- a/quincy/api.py +++ b/quincy/api.py @@ -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() diff --git a/quincy/v1_api.py b/quincy/v1_api.py index fd1694e..4744823 100644 --- a/quincy/v1_api.py +++ b/quincy/v1_api.py @@ -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) + diff --git a/quincy/v1_impl.py b/quincy/v1_impl.py index fc36b23..e94b8b0 100644 --- a/quincy/v1_impl.py +++ b/quincy/v1_impl.py @@ -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() diff --git a/setup.cfg b/setup.cfg index 5b123b7..dfa7753 100644 --- a/setup.cfg +++ b/setup.cfg @@ -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)