Merge branch 'master' of ssh://git.planet-lab.org/git/plstackapi into HEAD
diff --git a/planetstack/core/models/slice.py b/planetstack/core/models/slice.py
index 1f29f0e..6e1d163 100644
--- a/planetstack/core/models/slice.py
+++ b/planetstack/core/models/slice.py
@@ -149,3 +149,14 @@
             slices = Slice.select_by_user(user)
             qs = SliceDeployments.objects.filter(slice__in=slices)
         return qs    
+
+    def get_cpu_stats(self):
+        filter = 'project_id=%s'%self.tenant_id
+        return monitor.get_meter('cpu',filter,None)
+
+    def get_bw_stats(self):
+        filter = 'project_id=%s'%self.tenant_id
+        return monitor.get_meter('network.outgoing.bytes',filter,None)
+
+    def get_node_stats(self):
+        return len(self.slice.slivers)
diff --git a/planetstack/core/models/sliver.py b/planetstack/core/models/sliver.py
index d9d2028..601afbb 100644
--- a/planetstack/core/models/sliver.py
+++ b/planetstack/core/models/sliver.py
@@ -13,6 +13,7 @@
 from core.models import Flavor
 from django.contrib.contenttypes import generic
 from planetstack.config import Config
+from monitor import driver as monitor
 
 config = Config()
 
@@ -141,3 +142,15 @@
             slices = Slice.select_by_user(user)
             qs = Sliver.objects.filter(slice__in=slices)
         return qs
+
+    def get_cpu_stats(self):
+        filter = 'instance_id=%s'%self.sliver_id
+        return monitor.get_meter('cpu',filter,None)
+
+    def get_bw_stats(self):
+        filter = 'instance_id=%s'%self.sliver_id
+        return monitor.get_meter('network.outgoing.bytes',filter,None)
+
+    def get_node_stats(self):
+        # Note sure what should go back here
+        return 1
diff --git a/planetstack/monitor/__init__.py b/planetstack/monitor/__init__.py
new file mode 100644
index 0000000..1dd5074
--- /dev/null
+++ b/planetstack/monitor/__init__.py
@@ -0,0 +1,3 @@
+from observer import ceilometer
+
+driver = ceilometer.CeilometerDriver()
diff --git a/planetstack/monitor/monitordriver.py b/planetstack/monitor/monitordriver.py
new file mode 100644
index 0000000..f7eb1b9
--- /dev/null
+++ b/planetstack/monitor/monitordriver.py
@@ -0,0 +1,19 @@
+# Implement this interface
+# to serve as a driver for analytics
+
+class DashboardStatistics(dict):
+    def __init__(self):
+        self['stat_list'] = []
+        self['average'] = 0
+        self['sum'] = 0
+        self['unit'] = 'units'
+        # stat_list is a list of dicts
+        # [ {'timestamp': datetime, 'value': value} ]
+
+
+class MonitorDriver:
+    def __init__(self):
+        pass
+
+    def get_meter(self, meter_name, credentials):
+        pass
diff --git a/planetstack/openstack_observer/ceilometer.py b/planetstack/openstack_observer/ceilometer.py
new file mode 100644
index 0000000..11e9851
--- /dev/null
+++ b/planetstack/openstack_observer/ceilometer.py
@@ -0,0 +1,99 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+from ceilometerclient import client
+from os import environ as env
+import keystoneclient.v2_0.client as ksclient
+import re
+import datetime
+import time
+from monitor.monitordriver import *
+
+
+def cli_to_array(cli_query):
+    '''This converts from the cli list of queries to what is required
+    by the python api.
+    so from:
+    "this<=34;that=foo"
+    to
+    "[{field=this,op=le,value=34},{field=that,op=eq,value=foo}]"
+    '''
+    if cli_query is None:
+        return None
+
+    op_lookup = {'!=': 'ne',
+                 '>=': 'ge',
+                 '<=': 'le',
+                 '>': 'gt',
+                 '<': 'lt',
+                 '=': 'eq'}
+
+    def split_by_op(string):
+        # two character split (<=,!=)
+        frags = re.findall(r'([[a-zA-Z0-9_.]+)([><!]=)([^ -,\t\n\r\f\v]+)',
+                           string)
+        if len(frags) == 0:
+            #single char split (<,=)
+            frags = re.findall(r'([a-zA-Z0-9_.]+)([><=])([^ -,\t\n\r\f\v]+)',
+                               string)
+        return frags
+
+    opts = []
+    queries = cli_query.split(';')
+    for q in queries:
+        frag = split_by_op(q)
+        if len(frag) > 1:
+            raise ValueError('incorrect seperator %s in query "%s"' %
+                             ('(should be ";")', q))
+        if len(frag) == 0:
+            raise ValueError('invalid query %s' % q)
+        query = frag[0]
+        opt = {}
+        opt['field'] = query[0]
+        opt['op'] = op_lookup[query[1]]
+        opt['value'] = query[2]
+        opts.append(opt)
+    return opts
+
+def meters_to_stats(meters):
+    stats = DashboardStatistics()
+    for m in meters:
+        timestamp = datetime.datetime.strptime(m.duration_start,'%Y-%m-%dT%H:%M:%S')
+        stats.stat_list.append({'timestamp':timestamp, 'value':m.sum})
+        stats.sum+=m.sum
+        stats.average+=m.sum
+        stats.unit = 'ns'
+
+    stats.average/=len(meters)
+    return stats
+        
+                
+
+class CeilometerDriver(MonitorDriver):
+    def get_meter(self, meter, object_filter, keystone):
+        if (not keystone):
+            keystone = {}
+            keystone['username']=env['OS_USERNAME']
+            keystone['password']=env['OS_PASSWORD']
+            keystone['auth_url']=env['OS_AUTH_URL']
+            keystone['tenant_name']=env['OS_TENANT_NAME']
+
+        ceilometer_client = client._get_ksclient(**keystone)
+        token = ceilometer_client.auth_token
+
+        ceilo_endpoint = client._get_endpoint(ceilometer_client, **keystone)
+
+        ceilometer = client.Client('2',endpoint = ceilo_endpoint, token = lambda: token)
+
+        cur_ts = datetime.datetime.fromtimestamp(time.time()-86400)
+        str_ts = cur_ts.strftime('%Y-%m-%dT%H:%M:%S')
+        
+        filter=';'.join([object_filter,'timestamp>%s'%str_ts])
+        #query = cli_to_array("project_id=124de34266b24f57957345cdb43cc9ff;timestamp>2014-12-11T00:00:00")
+        query = cli_to_array(filter)
+
+        meters = ceilometer.statistics.list(meter,q=query,period=3600)
+
+        stats = meters_to_stats(meters)
+        return stats
+