add during test webiu
diff --git a/wally/sensors.html b/wally/sensors.html
new file mode 100644
index 0000000..77e3cf6
--- /dev/null
+++ b/wally/sensors.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<style>
+ @import url(http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:400,700);
+ @import url(http://square.github.io/cubism/style.css);
+</style>
+<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
+<script src="http://square.github.io/cubism/cubism.v1.js"></script>
+<div id="body"> <div id="graph" /></div>
+
+<script>
+
+// create context and horizon
+var context = cubism.context().serverDelay(3 * 1000).step(1000).size(1000)
+var horizon = context.horizon().extent([0, 100])
+
+// define metric accessor
+function wally_source(name) {
+ function selector(start, stop, step, callback){
+ function on_result(data) {
+ callback(null, data);
+ };
+
+ url = "/sensors?start=" + start + "&stop=" + stop + "&step=" + step + "&name=" + name;
+ d3.json(url, on_result);
+ }
+
+ return context.metric(selector, name);
+}
+
+// draw graph
+var metrics = ["testnodes:io_q", "testnodes:cpu"];
+horizon.metric(wally_source);
+
+d3.select("#graph").selectAll(".horizon")
+ .data(metrics)
+ .enter()
+ .append("div")
+ .attr("class", "horizon")
+ .call(horizon.height(120));
+
+// set rule
+d3.select("#body").append("div")
+ .attr("class", "rule")
+ .call(context.rule());
+
+// set focus
+context.on("focus", function(i) {
+ d3.selectAll(".value")
+ .style( "right", i == null ? null : context.size() - i + "px");
+});
+
+// set axis
+var axis = context.axis()
+d3.select("#graph").append("div").attr("class", "axis").append("g").call(axis);
+
+</script>
diff --git a/wally/webui.py b/wally/webui.py
new file mode 100644
index 0000000..5c8e989
--- /dev/null
+++ b/wally/webui.py
@@ -0,0 +1,93 @@
+import time
+import random
+import os.path
+import logging
+import calendar
+import datetime
+import threading
+
+import cherrypy
+from cherrypy import tools
+
+import wally
+
+logger = logging.getLogger("wally.webui")
+
+
+def to_timestamp(str_datetime):
+ dt, str_gmt_offset = str_datetime.split("GMT", 1)
+ dt = dt.strip().split(" ", 1)[1]
+ dto = datetime.datetime.strptime(dt, "%b %d %Y %H:%M:%S")
+ timestamp = calendar.timegm(dto.timetuple())
+ str_gmt_offset = str_gmt_offset.strip().split(" ", 1)[0]
+ gmt_offset = int(str_gmt_offset)
+ gmt_offset_sec = gmt_offset // 100 * 3600 + (gmt_offset % 100) * 60
+ return timestamp - gmt_offset_sec
+
+
+def backfill_thread(dstore):
+ with dstore.lock:
+ for i in range(600):
+ dstore.data['disk_io'].append(int(random.random() * 100))
+ dstore.data['net_io'].append(int(random.random() * 100))
+
+ while True:
+ time.sleep(1)
+ with dstore.lock:
+ dstore.data['disk_io'].append(int(random.random() * 100))
+ dstore.data['net_io'].append(int(random.random() * 100))
+
+
+class WebWally(object):
+
+ def __init__(self, sensors_data_storage):
+ self.storage = sensors_data_storage
+
+ @cherrypy.expose
+ @tools.json_out()
+ def sensors(self, start, stop, step, name):
+ try:
+ start = to_timestamp(start)
+ stop = to_timestamp(stop)
+
+ with self.storage.lock:
+ data = self.storage.data[name]
+ except Exception:
+ logger.exception("During parse input data")
+ raise cherrypy.HTTPError("Wrong date format")
+
+ if step != 1000:
+ raise cherrypy.HTTPError("Step must be equals to 1s")
+
+ num = stop - start
+
+ if len(data) > num:
+ data = data[-num:]
+ else:
+ data = [0] * (num - len(data)) + data
+
+ return data
+
+ @cherrypy.expose
+ def index(self):
+ idx = os.path.dirname(wally.__file__)
+ idx = os.path.join(idx, "sensors.html")
+ return open(idx).read()
+
+
+def web_main_thread(sensors_data_storage):
+
+ cherrypy.config.update({'environment': 'embedded',
+ 'server.socket_port': 8089,
+ 'engine.autoreload_on': False})
+
+ th = threading.Thread(None, backfill_thread, "backfill_thread",
+ (sensors_data_storage,))
+ th.daemon = True
+ th.start()
+
+ cherrypy.quickstart(WebWally(sensors_data_storage), '/')
+
+
+def web_main_stop():
+ cherrypy.engine.stop()