--- /dev/null
+<table>
+ {% for k, v in items %}
+ <tr>
+ <td>{{ k }}</td>
+ <td>{{ "%.2f" % v }}%</td>
+ </tr>
+ {% end %}
+</table>
{{ _("Architecture") }}
</td>
<td>
- {{ profile.arch }}
+ {{ profile.cpu.arch }}
</td>
</tr>
<tr>
</td>
</tr>
</table>
+
+ {% if profile.hypervisor %}
+ <h4>{{ _("Hypervisor") }}</h4>
+
+ <table>
+ <tr>
+ <td>
+ {{ _("Vendor") }}
+ </td>
+ <td>
+ {{ profile.hypervisor.vendor }}
+ </td>
+ </tr>
+ <tr>
+ <td>
+ {{ _("Model") }}
+ </td>
+ <td>
+ {{ profile.hypervisor.model or _("Unknown") }}
+ </td>
+ </tr>
+ <tr>
+ <td>
+ {{ _("Type") }}
+ </td>
+ <td>
+ {{ profile.hypervisor.type }}
+ </td>
+ </tr>
+ </table>
+ {% end %}
<h4>{{ _("Hardware") }}</h4>
<table>
{{ _("Vendor") }}
</td>
<td>
- {{ profile.cpu.vendor }}
+ <a href="/vendor/cpu/{{ profile.cpu.vendor }}">{{ profile.cpu.vendor }}</a>
</td>
</tr>
<tr>
{{ _("Model") }}
</td>
<td>
- <!-- XXX hack - becuase module_string does not exist, yet -->
- {{ profile.cpu._data.get("model_string", _("Not available")) }}
+ {{ profile.cpu.model_string or _("Not available") }}
</td>
+ </tr>
+<!--
<tr>
<td>
{{ _("CPU flags") }}
{{ locale.list(profile.cpu.flags) }}
</td>
</tr>
+-->
+ <tr>
+ <td>
+ {{ _("Supports x86_64") }}
+ </td>
+ <td>
+ {% if profile.cpu.capable_64bit %}
+ YES
+ {% else %}
+ NO
+ {% end %}
+ </td>
+ </tr>
+ <tr>
+ <td>
+ {{ _("Supports PAE") }}
+ </td>
+ <td>
+ {% if profile.cpu.capable_pae %}
+ YES
+ {% else %}
+ NO
+ {% end %}
+ </td>
+ </tr>
+ <tr>
+ <td>
+ {{ _("Supports VT-x/AMD-V") }}
+ </td>
+ <td>
+ {% if profile.cpu.capable_virt %}
+ YES
+ {% else %}
+ NO
+ {% end %}
+ </td>
+ </tr>
<tr>
<td colspan="2">
<strong>{{ _("Memory") }}<strong>
<strong>{{ _("Devices") }}</strong>
</td>
</tr>
- {% for device in profile.devices %}
- <tr>
- <td>
- {{ device.subsystem.upper() }}
- </td>
- <td>
- <a href="/vendor/{{ device.subsystem.lower() }}/{{ device.vendor }}">{{ device.vendor }}</a>:<a
- href="/model/pci/{{ device.vendor }}/{{device.model }}">{{ device.model }}</a> •
- {{ device.vendor_string }}
- {{ device.model_string }}
- </td>
- </tr>
- {% end %}
+ <tr>
+ <td colspan="2">
+ <table>
+ {% for device in profile.devices %}
+ <tr>
+ <td>
+ {{ device.subsystem.upper() }}
+ </td>
+ <td>
+ <a href="/vendor/{{ device.subsystem.lower() }}/{{ device.vendor }}">{{ device.vendor_string }}</a>
+ </td>
+ <td>
+ <a href="/model/pci/{{ device.vendor }}/{{device.model }}">{{ device.model_string }}</a>
+ </td>
+ <td>
+ {{ device.driver or " " }}
+ </td>
+ </tr>
+ {% end %}
+ </table>
+ </td>
+ </tr>
</table>
<p class="links">
--- /dev/null
+{% extends "stasy-base-1.html" %}
+
+{% block title %}{% end block %}
+
+{% block content %}
+ {{ modules.StasyTable(cpu_vendors) }}
+{% end block %}
--- /dev/null
+{% extends "stasy-base-1.html" %}
+
+{% block title %}{% end block %}
+
+{% block content %}
+ {{ modules.StasyTable(is_virtual) }}
+
+ {{ modules.StasyTable(hypervisor_vendors) }}
+{% end block %}
--- /dev/null
+{% extends "stasy-base-1.html" %}
+
"ReleaseItem" : ReleaseItemModule,
"SidebarBanner" : SidebarBannerModule,
"SidebarRelease" : SidebarReleaseModule,
+ "StasyTable" : StasyTableModule,
"TrackerPeerList": TrackerPeerListModule,
},
xsrf_cookies = True,
self.add_handlers(r"stasy\.ipfire\.org", [
(r"/", StasyIndexHandler),
(r"/profile/([a-z0-9]{40})", StasyProfileHandler),
+ (r"/statistics/cpu", StasyStatsCPUHandler),
+ (r"/statistics/virtual", StasyStatsVirtualHandler),
] + static_handlers)
# source.ipfire.org
from planet import Planet
from releases import Releases
from settings import Settings as Config
+from stasy import Stasy
from tracker import Tracker
--- /dev/null
+#!/usr/bin/python
+
+import hwdata
+import logging
+import pymongo
+
+from misc import Singleton
+
+DATABASE_HOST = ["irma.ipfire.org", "madeye.ipfire.org"]
+DATABASE_NAME = "stasy"
+
+MEMORY_CONSTRAINTS = (0, 64, 128, 256, 512, 1024, 2048, 4096, 8128, 16384)
+
+class ProfileDict(object):
+ def __init__(self, data):
+ self._data = data
+
+
+class ProfileCPU(ProfileDict):
+ @property
+ def arch(self):
+ return self._data.get("arch")
+
+ @property
+ def vendor(self):
+ return self._data.get("vendor")
+
+ @property
+ def model(self):
+ return self._data.get("model")
+
+ @property
+ def model_string(self):
+ return self._data.get("model_string")
+
+ @property
+ def flags(self):
+ return self._data.get("flags")
+
+ @property
+ def capable_64bit(self):
+ return "lm" in self.flags
+
+ @property
+ def capable_pae(self):
+ return "pae" in self.flags
+
+ @property
+ def capable_virt(self):
+ return "vmx" in self.flags or "svm" in self.flags
+
+
+class ProfileHypervisor(ProfileDict):
+ def __repr__(self):
+ return "<%s %s-%s>" % (self.__class__.__name__, self.vendor, self.type)
+
+ @property
+ def vendor(self):
+ return self._data.get("vendor")
+
+ @property
+ def model(self):
+ return self._data.get("model")
+
+ @property
+ def type(self):
+ return self._data.get("type")
+
+
+class ProfileDevice(ProfileDict):
+ subsystem2class = {
+ "pci" : hwdata.PCI,
+ "usb" : hwdata.USB,
+ }
+
+ @property
+ def model(self):
+ return self._data.get("model")
+
+ @property
+ def model_string(self):
+ cls = self.subsystem2class[self.subsystem]
+
+ return cls().get_device(self.vendor, self.model)
+
+ @property
+ def subsystem(self):
+ return self._data.get("subsystem")
+
+ @property
+ def vendor(self):
+ return self._data.get("vendor")
+
+ @property
+ def vendor_string(self):
+ cls = self.subsystem2class[self.subsystem]
+
+ return cls().get_vendor(self.vendor)
+
+ @property
+ def driver(self):
+ return self._data.get("driver")
+
+
+class Profile(ProfileDict):
+ def __init__(self, public_id, updated, data):
+ ProfileDict.__init__(self, data)
+
+ self.public_id = public_id
+ self.updated = updated
+
+ def __repr__(self):
+ return "<%s %s>" % (self.__class__.__name__, self.public_id)
+
+ @property
+ def cpu(self):
+ return ProfileCPU(self._data.get("cpu"))
+
+ @property
+ def devices(self):
+ devices = []
+ for d in self._data.get("devices"):
+ d = ProfileDevice(d)
+
+ if d.driver in ("usb", "hub"):
+ continue
+
+ devices.append(d)
+
+ return devices
+
+ @property
+ def hypervisor(self):
+ if self.virtual:
+ return ProfileHypervisor(self._data.get("hypervisor"))
+
+ @property
+ def virtual(self):
+ return self.system.get("virtual")
+
+ @property
+ def system(self):
+ return self._data.get("system")
+
+ @property
+ def release(self):
+ return self.system.get("release")
+
+ @property
+ def kernel(self):
+ return self.system.get("kernel_release")
+
+ @property
+ def memory(self):
+ return self.system.get("memory")
+
+ @property
+ def root_size(self):
+ return self.system.get("root_size")
+
+
+
+class Stasy(object):
+ __metaclass__ = Singleton
+
+ def __init__(self):
+ # Initialize database connection
+ self._conn = pymongo.Connection(DATABASE_HOST)
+ self._db = self._conn[DATABASE_NAME]
+
+ def get_profile_count(self):
+ # XXX need to implement something to get profiles updated since
+ # a given date
+
+ # All distinct profiles (based on public_id)
+ return self._db.profiles.distinct("public_id").count()
+
+ #def _get_profile_cursor(self, public_id):
+ # c = self._db.profiles.find({ "public_id" : public_id })
+ # c.sort("updated", pymongo.ASCENDING)
+ #
+ # return c
+
+ def get_profile(self, public_id):
+ # XXX should only find one object in the end
+ for p in self._db.profiles.find({ "public_id" : public_id }):
+ p = Profile(p.get("public_id"), p.get("updated"), p.get("profile"))
+
+ return p
+
+ def get_profiles(self):
+ # XXX needs nicer database query
+ profiles = []
+ for p in self._db.profiles.find():
+ if not p.get("public_id") in profiles:
+ profiles.append(p.get("public_id"))
+
+ return profiles
+
+ @property
+ def secret_ids(self):
+ return self._db.profiles.distinct("secret_id")
+
+ @property
+ def cpus(self):
+ return self._db.profiles.distinct("profile.cpu")
+
+ @property
+ def cpu_vendors(self):
+ return self._db.profiles.distinct("profile.cpu.vendor")
+
+ @property
+ def cpu_map(self):
+ cpus = {}
+
+ for vendor in self.cpu_vendors:
+ cpus[vendor] = \
+ self._db.profiles.find({
+ "profile.cpu.vendor" : vendor
+ }).count()
+
+ return cpus
+
+ @property
+ def memory_map(self):
+ memory = {}
+
+ for i in range(len(MEMORY_CONSTRAINTS) - 1):
+ min, max = MEMORY_CONSTRAINTS[i:i+2]
+
+ memory[min, max] = \
+ self._db.profiles.find(
+ { "profile.system.memory" : {
+ "$gte" : min * 1024, "$lt" : max * 1024
+ }
+ }).count()
+
+ return memory
+
+ @property
+ def memory_average(self):
+ memory = 0
+
+ all = self._db.profiles.find()
+
+ # XXX ugly. needs to be done by group()
+ for m in all:
+ if not m.has_key("profile"):
+ continue
+ memory += int(m.get("profile").get("system").get("memory"))
+
+ return (memory / all.count()) / 1024
+
+ @property
+ def hypervisor_vendors(self):
+ return self._db.profiles.distinct("profile.hypervisor.vendor")
+
+ @property
+ def hypervisor_map(self):
+ hypervisors = {}
+
+ for hypervisor in self.hypervisor_vendors:
+ hypervisors[hypervisor] = \
+ self._db.profiles.find({
+ "profile.hypervisor.vendor" : hypervisor
+ }).count()
+
+ return hypervisors
+
+ @property
+ def hypervisor_models(self):
+ return self._db.profiles.distinct("profile.hypervisor.model")
+
+ @property
+ def virtual_map(self):
+ virtual = {
+ True: None,
+ False: None,
+ }
+
+ for k in virtual.keys():
+ virtual[k] = \
+ self._db.profiles.find({ "profile.system.virtual": k }).count()
+
+ return virtual
+
+ @property
+ def languages(self):
+ return self._db.profiles.distinct("profile.system.language")
+
+ @property
+ def vendors(self):
+ return self._db.profiles.distinct("profile.system.vendor")
+
+ @property
+ def vendor_map(self):
+ vendors = {}
+
+ for vendor in self.vendors:
+ vendors[vendor] = \
+ self._db.profiles.find({
+ "profile.system.vendor" : vendor
+ }).count()
+
+ return vendors
+
+ @property
+ def models(self):
+ return self._db.profiles.distinct("profile.system.model")
+
+
+
+if __name__ == "__main__":
+ s = Stasy()
+
+ print s.get_profile("0" * 40)
+ print s.cpu_vendors
+ for id in s.secret_ids:
+ print "\t", id
+
+ #for p in s._db.profiles.find():
+ # print p
+
+ print s.cpu_map
+ print s.memory_map
+ print s.memory_average
+ print s.hypervisor_vendors
+ print s.hypervisor_models
+ print s.languages
+ print s.vendors
+ print s.vendor_map
+ print s.models
+ print s.cpus
+
+ p = s.get_profile("0b5f4fe2162fdfbfa29b632610e317078fa70d34")
+ print p
+ print p.hypervisor
import tornado.web
+import backend
+
from handlers_base import *
class StasyBaseHandler(BaseHandler):
raise tornado.web.HTTPError(404, "Profile not found: %s" % profile_id)
self.render("stasy-profile.html", profile=profile)
+
+
+class StasyStatsCPUHandler(StasyBaseHandler):
+ def get(self):
+ return self.render("stasy-stats-cpus.html",
+ cpu_vendors = self.stasy.cpu_map)
+
+
+class StasyStatsVirtualHandler(StasyBaseHandler):
+ def get(self):
+ return self.render("stasy-stats-virtual.html",
+ hypervisor_vendors = self.stasy.hypervisor_map,
+ is_virtual = self.stasy.virtual_map)
+++ /dev/null
-#!/usr/bin/python
-
-import logging
-import pymongo
-
-DATABASE_HOST = ["irma.ipfire.org", "madeye.ipfire.org"]
-DATABASE_NAME = "stasy"
-
-class ProfileDict(object):
- def __init__(self, data):
- self._data = data
-
- logging.debug("New: %s" % self._data)
-
- def __repr__(self):
- return self.__str__()
-
- def __str__(self):
- return "<%s %s>" % (self.__class__.__name__, self.public_id)
-
- def __getattr__(self, key):
- try:
- return self._data[key]
- except KeyError:
- raise AttributeError, key
-
- def __setattr(self, key, val):
- self._data[key] = val
-
-
-class ProfileCPU(ProfileDict):
- @property
- def capable_64bit(self):
- return "lm" in self.flags
-
- @property
- def capable_pae(self):
- return "pae" in self.flags
-
-
-class ProfileHypervisor(ProfileDict):
- pass
-
-
-class ProfileDevice(ProfileDict):
- @property
- def model_string(self):
- return "XXX"
-
- @property
- def vendor_string(self):
- return "XXX"
-
-
-class Profile(ProfileDict):
- def __repr__(self):
- return "<%s %s>" % (self.__class__.__name__, self.public_id)
-
- @property
- def cpu(self):
- return ProfileCPU(self._data["cpu"])
-
- @property
- def hypervisor(self):
- return ProfileHypervisor(self._data["hypervisor"])
-
- @property
- def devices(self):
- return [ProfileDevice(d) for d in self._data["devices"]]
-
-
-class StasyDatabase(object):
- def __init__(self):
- # Initialize database connection
- self._conn = pymongo.Connection(DATABASE_HOST)
- self._db = self._conn[DATABASE_NAME]
-
- def get_profile_count(self):
- # XXX need to implement something to get profiles updated since
- # a given date
-
- # All distinct profiles (based on public_id)
- c = self._db.profiles.find().distinct("public_id")
-
- return c.count()
-
- def _get_profile_cursor(self, public_id):
- c = self._db.profiles.find({ "public_id" : public_id })
- c.sort("updated", pymongo.ASCENDING)
-
- return c
-
- def get_latest_profile(self, public_id):
- # XXX still finds first one
- for p in self._get_profile_cursor(public_id).limit(1):
- return Profile(p)
-
- def get_profiles(self):
- # XXX needs nicer database query
- profiles = []
- for p in self._db.profiles.find():
- p = Profile(p)
- if not p.public_id in profiles:
- profiles.append(p.public_id)
-
- return profiles
-
- @property
- def cpus(self):
- return self._db.profiles.distinct("profile.cpu")
-
- @property
- def cpu_vendors(self):
- return self._db.profiles.distinct("profile.cpu.vendor")
-
- @property
- def cpu_map(self):
- cpus = {}
-
- for vendor in self.cpu_vendors:
- cpus[vendor] = \
- self._db.profiles.find({ "profile.cpu.vendor" : vendor }).count()
-
- return cpus
-
- @property
- def hypervisor_vendors(self):
- return self._db.profiles.distinct("profile.hypervisor.vendor")
-
- @property
- def hypervisor_models(self):
- return self._db.profiles.distinct("profile.hypervisor.model")
-
- @property
- def secret_ids(self):
- return self._db.profiles.distinct("secret_id")
-
- @property
- def languages(self):
- return self._db.profiles.distinct("profile.system.language")
-
- @property
- def vendors(self):
- return self._db.profiles.distinct("profile.system.vendor")
-
- @property
- def models(self):
- return self._db.profiles.distinct("profile.system.model")
-
-
-class Stasy(object):
- def __init__(self):
- self.db = StasyDatabase()
-
- def get_profile(self, public_id):
- return self.db.get_latest_profile(public_id)
-
- def get_profiles(self):
- return self.db.get_profiles()
-
-
-if __name__ == "__main__":
- s = Stasy()
-
- print s.get_profile("0" * 40)
- print s.db.cpu_vendors
- for id in s.db.secret_ids:
- print "\t", id
-
- for p in s.db._db.profiles.find():
- print p
-
- print s.db.cpu_map
- print s.db.hypervisor_vendors
- print s.db.hypervisor_models
- print s.db.languages
- print s.db.vendors
- print s.db.models
- print s.db.cpus
return self.render_string("modules/tracker-peerlist.html",
peers=[Row(p) for p in peers], percentages=percentages)
+
+
+class StasyTableModule(UIModule):
+ def render(self, items):
+ hundred_percent = 0
+ for v in items.values():
+ hundred_percent += v
+
+ if hundred_percent:
+ _items = []
+ for k in sorted(items.keys()):
+ v = float(items[k] * 100) / hundred_percent
+ _items.append((k, v))
+ items = _items
+
+ print items
+
+ return self.render_string("modules/stasy-table.html", items=items)