Very hard to break down and not neccessary.
table.blocks td.block2 {
background-color: #f5f5f5;
}
+
+table.fireinfo {
+ width: 45em;
+ margin-left: 1.5em;
+}
+
+table.fireinfo td.key {
+ width: 12.5em;
+}
+
+table.fireinfo td.value {
+ width: 32.5em;
+}
+
+table.cpufeatures tr {
+ line-height: 1.2em;
+}
+
+table.cpufeatures td {
+ padding-left: 0.1em;
+ padding-right: 0.1em;
+}
+
+table.cpufeatures td.enabled {
+ border: 1px solid #88ff88;
+ background-color: #aaffaa;
+}
+
+table.cpufeatures td.disabled {
+ border: 1px solid #ff8888;
+ background-color: #ff9999;
+}
+
+table.stats {
+ width: 45em;
+ margin-left: 1.5em;
+}
+
+table.stats td.key {
+ width: 12.5em;
+}
+
+table.stats td.value {
+ width: 2.5em;
+ text-align: right;
+}
+
+table.stats td.bar {
+ width: 30em;
+}
+
+table.stats td.bar p {
+ background-color: #880400;
+}
--- /dev/null
+<table class="fireinfo">
+ {% for group, devices in groups %}
+ <tr class="vendor">
+ <td colspan="3">
+ <br />
+ <strong>{{ _(group) }}</strong>
+ </td>
+ </tr>
+ {% for device in devices %}
+ <tr class="device">
+ <td>
+ <!-- XXX add margin in CSS -->
+ <img src="{{ static_url("images/icons/bus-%s.png" % device.subsystem) }}"
+ alt="{{ device.subsystem.upper() }}" />
+ </td>
+ <td>
+ <a class="vendor" href="/vendor/{{ device.subsystem }}/{{ device.vendor }}">
+ {{ device.vendor_string }}
+ </a>
+ -
+ <a href="/model/{{ device.subsystem }}/{{ device.vendor }}/{{ device.model }}">
+ {{ device.model_string or "N/A (%s)" % device.model }}
+ </a>
+ <br />
+ {{ _("Module") }}: {{ device.driver or "N/A" }}
+ </td>
+ </tr>
+ {% end %}
+ {% end %}
+</table>
-<table>
+<table class="stats">
{% for k, v in items %}
<tr>
- <td>{{ k }}</td>
- <td>{{ "%.2f" % v }}%</td>
+ <td class="key">{{ k }}</td>
+ <td class="bar"><p style="{{ "width: %.2f%%" % v }}"> </p></td>
+ <td class="value">{{ "%.2f" % v }}%</td>
</tr>
{% end %}
</table>
+<br class="clear" />
{% block content %}
<h3>{{ _("Statistical evaluation service") }}</h3>
- {% for p in profiles %}
- <a href="/profile/{{ p }}">{{ p }}</a>
- {% end %}
+ <p>
+ Please enter your profile ID and have a look of the hardware components
+ that are installed on your system:
+ </p>
+
+ <form name="profile" method="POST">
+ {{ xsrf_form_html() }}
+ <p>
+ <input type="text" name="profile_id" size="40" maxlength="40" />
+ <input type="submit" value="{{ _("Show profile") }}" />
+ </p>
+ </form>
+ <br class="clear" />
+
+ <h3>XXX Just for now...</h3>
+ <p>
+ {% for p in profiles %}
+ <a href="/profile/{{ p }}">{{ p }}</a>
+ {% end %}
+ </p>
{% end block %}
--- /dev/null
+{% extends "stasy-base-1.html" %}
+
+{% block content %}
+ <h3>{{ vendor_name }} - {{ model_name or model_id }}</h3>
+ <p>
+ This device is installed on approximately {{ "%.2f" % percentage }}% of
+ all systems in the database.
+ </p>
+{% end block %}
--- /dev/null
+{% extends "stasy-base-2.html" %}
+
+{% block title %}{{ _("Profile") }} {{ profile.public_id }}{% end block %}
+
+{% block content %}
+ <h3>{{ _("Profile") }} {{ profile.public_id }}</h3>
+
+ <img src="{{ static_url("images/flags/%s.png" % profile.country_code) }}"
+ class="floatTR" alt="{{ profile.country_code }}" />
+
+ <table class="fireinfo">
+ <tr>
+ <td class="key">
+ {{ _("Vendor") }}
+ </td>
+ <td class="value">
+ {{ profile.vendor }}
+ </td>
+ </tr>
+ <tr>
+ <td class="key">
+ {{ _("Model") }}
+ </td>
+ <td class="value">
+ {{ profile.model }}
+ </td>
+ </tr>
+ </table>
+
+ <h4>{{ _("Operating system") }}</h4>
+ <table class="fireinfo">
+ <tr>
+ <td class="key">
+ {{ _("Version") }}
+ </td>
+ <td class="value">
+ {{ profile.release }}
+ </td>
+ </tr>
+ <tr>
+ <td class="key">
+ {{ _("Architecture") }}
+ </td>
+ <td class="value">
+ {{ profile.cpu.arch }}
+ </td>
+ </tr>
+ <tr>
+ <td class="key">
+ {{ _("Kernel version") }}
+ </td>
+ <td class="value">
+ {{ profile.kernel }}
+ </td>
+ </tr>
+ </table>
+
+ {% if profile.hypervisor %}
+ <h4>{{ _("Hypervisor") }}</h4>
+ <p>
+ {{ _("This machine is running in a virtual environment.") }}
+ </p>
+
+ <table class="fireinfo">
+ <tr>
+ <td class="key">
+ {{ _("Vendor") }}
+ </td>
+ <td class="value">
+ {{ profile.hypervisor.vendor }}
+ </td>
+ </tr>
+ <tr>
+ <td class="key">
+ {{ _("Type") }}
+ </td>
+ <td class="value">
+ {{ profile.hypervisor.type }}
+ </td>
+ </tr>
+ </table>
+ {% end %}
+
+ <h4>{{ _("Hardware") }}</h4>
+ <table class="fireinfo">
+ <tr>
+ <td colspan="2">
+ <strong>{{ _("CPU") }}</strong>
+ </td>
+ </tr>
+ <tr>
+ <td class="key">
+ {{ _("Vendor") }}
+ </td>
+ <td class="value">
+ <a href="/stats/cpus">{{ profile.cpu.vendor }}</a>
+ </td>
+ </tr>
+ <tr>
+ <td class="key">
+ {{ _("Model") }}
+ </td>
+ <td class="value">
+ {{ profile.cpu.model_string or _("Not available") }}
+ </td>
+ </tr>
+ <tr>
+ <td class="key">
+ {{ _("Core count") }}
+ </td>
+ <td class="value">
+ {{ profile.cpu.count }}
+ </td>
+ </tr>
+ <tr>
+ <td class="key">
+ {{ _("Speed") }}
+ </td>
+ <td class="value">
+ {{ profile.cpu.speed }} MHz (Bogomips: {{ profile.cpu.bogomips }})
+ </td>
+ </tr>
+ <tr>
+ <td class="key">
+ {{ _("Supported features") }}
+ </td>
+ <td class="value">
+ <table class="cpufeatures">
+ <tr>
+ {% if profile.cpu.capable_64bit %}
+ <td class="enabled">
+ {% else %}
+ <td class="disabled">
+ {% end %}
+ {{ _("64 bit") }}
+ <td>
+
+ {% if profile.cpu.capable_pae %}
+ <td class="enabled">
+ {% else %}
+ <td class="disabled">
+ {% end %}
+ {{ _("PAE") }}
+ <td>
+
+ {% if profile.cpu.capable_virt %}
+ <td class="enabled">
+ {% else %}
+ <td class="disabled">
+ {% end %}
+ {{ _("VT-x/AMD-V") }}
+ <td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <strong>{{ _("Memory") }}<strong>
+ </td>
+ </tr>
+ <tr>
+ <td class="key">
+ {{ _("Size") }}
+ </td>
+ <td class="value">
+ {{ format_size(profile.memory) }}
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <strong>{{ _("Disk") }}<strong>
+ </td>
+ </tr>
+ <tr>
+ <td class="key">
+ {{ _("Size") }}
+ </td>
+ <td class="value">
+ {{ format_size(profile.root_size) }}
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ {{ modules.StasyDeviceTable(profile.devices) }}
+ </td>
+ </tr>
+ </table>
+ <br class="clear" />
+
+ <h3>{{ _("Signature images") }}</h3>
+ <table>
+ {% for i in range(1) %}
+ <tr>
+ <td>
+ <!-- XXX need some bbcode here -->
+ <a href="http://i-use.ipfire.org/profile/{{ profile.public_id }}/{{ i }}.png">
+ <img src="http://i-use.ipfire.org/profile/{{ profile.public_id }}/{{ i }}.png"
+ alt="{{ _("Signature image") }}" />
+ </a>
+ </td>
+ </tr>
+ {% end %}
+ </table>
+
+ <p class="links">
+ {{ _("Last update") }}: {{ locale.format_date(profile.updated) }}
+ </p>
+{% end block %}
{% extends "stasy-base-1.html" %}
-{% block title %}{{ _("Profile") }} {{ profile.public_id }}{% end block %}
+{% block title %}{{ _("Profile lookup") }}{% end block %}
{% block content %}
- <h3>{{ _("Profile") }} {{ profile.public_id }}</h3>
+ <h3>{{ _("Profile lookup") }}</h3>
- <table>
- <tr>
- <td colspan="2">
- <strong>{{ _("Operating system") }}</strong>
- </td>
- </tr>
- <tr>
- <td>
- {{ _("Version") }}
- </td>
- <td>
- {{ profile.release }}
- </td>
- </tr>
- <tr>
- <td>
- {{ _("Architecture") }}
- </td>
- <td>
- {{ profile.cpu.arch }}
- </td>
- </tr>
- <tr>
- <td>
- {{ _("Kernel version") }}
- </td>
- <td>
- {{ profile.kernel }}
- </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>
- <tr>
- <td colspan="2">
- <strong>{{ _("CPU") }}</strong>
- </td>
- </tr>
- <tr>
- <td>
- {{ _("Vendor") }}
- </td>
- <td>
- <a href="/vendor/cpu/{{ profile.cpu.vendor }}">{{ profile.cpu.vendor }}</a>
- </td>
- </tr>
- <tr>
- <td>
- {{ _("Model") }}
- </td>
- <td>
- {{ profile.cpu.model_string or _("Not available") }}
- </td>
- </tr>
-<!--
- <tr>
- <td>
- {{ _("CPU flags") }}
- </td>
- <td>
- {{ 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>
- </td>
- </tr>
- <tr>
- <td>
- {{ _("Size") }}
- </td>
- <td>
- {{ int(profile.memory) / 1024 }} {{ _("MegaBytes") }}
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <strong>{{ _("Disk") }}<strong>
- </td>
- </tr>
- <tr>
- <td>
- {{ _("Size") }}
- </td>
- <td>
- {{ profile.root_size / 1024 }} {{ _("MegaBytes") }}
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <strong>{{ _("Devices") }}</strong>
- </td>
- </tr>
- <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">
- {{ _("Last update") }}: {{ locale.format_date(profile.updated) }}
+ <p>
+ Please enter your profile ID and have a look of the hardware components
+ that are installed on your system:
</p>
+
+ <form name="profile">
+ <p>
+ <input type="text" name="profile_id" size="40" maxlength="40" />
+ <input type="submit" value="{{ _("Show profile") }}" />
+ </p>
+ </form>
{% end block %}
--- /dev/null
+{% extends "stasy-base-2.html" %}
+
+{% block title %}{% end block %}
+
+{% block content %}
+ <h3>{{ _("CPU flags") }}</h3>
+ <p>
+ On this page we will examine which CPUs provide a specific feature.
+ These charts will help the IPFire developers to make decisions about
+ the operating system configuration.
+ </p>
+
+ <h4>{{ _("CPUs that support long mode") }}</h4>
+ <p>
+ For future planning it is important to know if there is enough hardware
+ support for a 64bit version of IPFire.
+ </p>
+ {{ modules.StasyTable(cpus_lm, sortby="percentage") }}
+
+ <h4>{{ _("CPUs with PAE") }}</h4>
+ <p>
+ This chart shows us which CPUs have got the PAE flag.
+ </p>
+ {{ modules.StasyTable(cpus_pae, sortby="percentage") }}
+{% end block %}
-{% extends "stasy-base-1.html" %}
+{% extends "stasy-base-2.html" %}
{% block title %}{% end block %}
{% block content %}
- {{ modules.StasyTable(cpu_vendors) }}
+ <h3>{{ _("CPU vendors") }}</h3>
+ <p>
+ This chart shows us which vendors is the most favorite for the CPUs
+ used in IPFire.
+ </p>
+ {{ modules.StasyTable(cpu_vendors, sortby="percentage") }}
+
+ <h3>{{ _("Speed") }}</h3>
+ <p>
+ The average speed of all systems in the database is:
+ <strong>{{ "%.2f" % average_speed }} MHz</strong>.
+ </p>
+ {{ modules.StasyTable(cpu_speeds) }}
+
+ <p class="links">
+ <a href="cpuflags">See statistics about common CPU flags</a>
+ </p>
{% end block %}
--- /dev/null
+{% extends "stasy-base-2.html" %}
+
+{% block title %}{% end block %}
+
+{% block content %}
+ <h3>{{ _("Language selection") }}</h3>
+ <p>
+ This will give a short overview about what languages are configured
+ on the IPFire webinterface.
+ </p>
+ {{ modules.StasyTable(languages, sortby="percentage") }}
+
+
+ <h3>{{ _("Geo locations") }}</h3>
+ <p>
+ This chart shows us in which country IPFire is running.
+ </p>
+ {{ modules.StasyTable(geo_locations, sortby="percentage") }}
+{% end block %}
--- /dev/null
+{% extends "stasy-base-2.html" %}
+
+{% block title %}{% end block %}
+
+{% block content %}
+ <h3>{{ _("Memory") }}</h3>
+ <p>
+ The average amount of memory of all systems in the database is:
+ <strong>{{ "%.2f" % average_memory }} MB</strong>.
+ </p>
+ {{ modules.StasyTable(memory) }}
+{% end block %}
--- /dev/null
+{% extends "stasy-base-2.html" %}
+
+{% block title %}{% end block %}
+
+{% block content %}
+ <h3>{{ _("Releases") }}</h3>
+ {{ modules.StasyTable(releases, sortby="percentage") }}
+
+ <h3>{{ _("Architectures") }}</h3>
+ {{ modules.StasyTable(arches, sortby="percentage") }}
+
+ <h3>{{ _("Kernels") }}</h3>
+ <p>
+ This chart gives an overview about what kernel the machines are
+ runnning.
+ </p>
+ {{ modules.StasyTable(kernels, sortby="percentage") }}
+{% end block %}
-{% extends "stasy-base-1.html" %}
+{% extends "stasy-base-2.html" %}
{% block title %}{% end block %}
{% block content %}
- {{ modules.StasyTable(is_virtual) }}
-
- {{ modules.StasyTable(hypervisor_vendors) }}
+ <h3>{{ _("Virtualization support") }}</h3>
+ <p>
+ IPFire is running very well in a virtual environment.
+ </p>
+ <p>
+ See this chart to get a clue about how many machines are running
+ virtually.
+ </p>
+ {{ modules.StasyTable(is_virtual, sortby="percentage") }}
+
+ <h4>{{ _("Hypervisors") }}</h4>
+ <p>
+ This is a list of all hypervisor vendors that IPFire is running on.
+ </p>
+ {{ modules.StasyTable(hypervisor_vendors, sortby="percentage") }}
{% end block %}
-{% extends "stasy-base-1.html" %}
+{% extends "stasy-base-2.html" %}
+{% block content %}
+ <h3>{{ _("Statistical accounting") }}</h3>
+ <p>
+ At this place you can find several charts to find out in what
+ specific way the hardware that is used for IPFire is ... XXX.
+ </p>
+
+ <table>
+ <tr>
+ <td><a href="/stats/cpus">{{ _("CPUs") }}</a></td>
+ <td><a href="/stats/cpuflags">{{ _("CPU flags") }}</a></td>
+ <td><a href="/stats/memory">{{ _("Memory") }}</a></td>
+ </tr>
+ <tr>
+ <td><a href="/stats/oses">{{ _("IPFire versions") }}</a></td>
+ <td><a href="/stats/virtual">{{ _("Virtualization") }}</a></td>
+ <td><a href="/stats/geo">{{ _("Geographical information") }}</a></td>
+ </tr>
+ </table>
+{% end block %}
--- /dev/null
+{% extends "stasy-base-1.html" %}
+
+{% block content %}
+ <h3>{{ vendor_name }}</h3>
+ <p>
+ This is a list of all devices this database knows about from
+ <strong>{{ vendor_name }}</strong>.
+ </p>
+
+ {{ modules.StasyDeviceTable(models) }}
+{% end block %}
"SidebarBanner" : SidebarBannerModule,
"SidebarRelease" : SidebarReleaseModule,
"StasyTable" : StasyTableModule,
+ "StasyDeviceTable" : StasyDeviceTableModule,
"TrackerPeerList": TrackerPeerListModule,
},
xsrf_cookies = True,
] + static_handlers)
# stasy.ipfire.org
- self.add_handlers(r"stasy\.ipfire\.org", [
+ self.add_handlers(r"(fireinfo|stasy)\.ipfire\.org", [
(r"/", StasyIndexHandler),
- (r"/profile/([a-z0-9]{40})", StasyProfileHandler),
- (r"/statistics/cpu", StasyStatsCPUHandler),
- (r"/statistics/virtual", StasyStatsVirtualHandler),
+ (r"/profile/([a-z0-9]{40})", StasyProfileDetailHandler),
+ (r"/vendor/(pci|usb)/([0-9a-f]{4})", StasyStatsVendorDetail),
+ (r"/model/(pci|usb)/([0-9a-f]{4})/([0-9a-f]{4})", StasyStatsModelDetail),
+
+ # Stats handlers
+ (r"/stats", StasyStatsHandler),
+ (r"/stats/cpus", StasyStatsCPUHandler),
+ (r"/stats/cpuflags", StasyStatsCPUFlagsHandler),
+ (r"/stats/geo", StasyStatsGeoHandler),
+ (r"/stats/memory", StasyStatsMemoryHandler),
+ (r"/stats/oses", StasyStatsOSesHandler),
+ (r"/stats/virtual", StasyStatsVirtualHandler),
] + static_handlers)
# i-use.ipfire.org
#!/usr/bin/python
+from __future__ import division
+
import hwdata
import logging
import pymongo
DATABASE_HOST = ["irma.ipfire.org", "madeye.ipfire.org"]
DATABASE_NAME = "stasy"
+CPU_SPEED_CONSTRAINTS = (0, 500, 1000, 1500, 2000, 2500, 3000, 3500)
MEMORY_CONSTRAINTS = (0, 64, 128, 256, 512, 1024, 2048, 4096, 8128, 16384)
class ProfileDict(object):
def vendor(self):
return self._data.get("vendor")
+ @property
+ def speed(self):
+ return self._data.get("speed")
+
+ @property
+ def bogomips(self):
+ return self._data.get("bogomips")
+
@property
def model(self):
return self._data.get("model")
def flags(self):
return self._data.get("flags")
+ @property
+ def count(self):
+ return self._data.get("count")
+
@property
def capable_64bit(self):
return "lm" in self.flags
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")
"usb" : hwdata.USB,
}
+ classid2name = {
+ "pci" : {
+ "00" : "unclassified",
+ "01" : "Mass storage",
+ "02" : "Network",
+ "03" : "Display",
+ "04" : "Multimedia",
+ "05" : "Memory controller",
+ "06" : "Bridge",
+ "07" : "Communication",
+ "08" : "Generic system peripheral",
+ "09" : "Input device",
+ "0a" : "Docking station",
+ "0b" : "Processor",
+ "0c" : "Serial bus",
+ "0d" : "Wireless",
+ "0e" : "Intelligent controller",
+ "0f" : "Satellite communications controller",
+ "10" : "Encryption controller",
+ "11" : "Signal processing controller",
+ "ff" : "Unassigned class",
+ },
+
+ "usb" : {
+ "00" : "???",
+ "01" : "Multimedia",
+ "02" : "Communication",
+ "03" : "Input device",
+ "05" : "Physical ???",
+ "06" : "Image ???",
+ "07" : "Printer",
+ "08" : "Mass storage",
+ "09" : "Hub",
+ "0a" : "CDC-Data ???",
+ "0b" : "Smart card ???",
+ "0d" : "Content Security ???",
+ "0e" : "Display",
+ "0f" : "Personal healthcare ???",
+ "dc" : "Diagnostic Device",
+ "e0" : "Wireless",
+ "ef" : "Misc",
+ "fe" : "Application specific ???",
+ "ff" : "Vendor specific ???",
+ }
+ }
+
+ def __cmp__(self, other):
+ return cmp(self.vendor, other.vendor) or \
+ cmp(self.model, other.model) or \
+ cmp(self.driver, other.driver)
+
@property
def model(self):
return self._data.get("model")
def driver(self):
return self._data.get("driver")
+ @property
+ def cls(self):
+ classid = self._data.get("deviceclass")
+
+ if self.subsystem == "pci":
+ classid = classid[:-4]
+ if len(classid) == 1:
+ classid = "0%s" % classid
+
+ elif self.subsystem == "usb" and classid:
+ classid = classid.split("/")[0]
+ classid = "%02x" % int(classid)
+
+ try:
+ return self.classid2name[self.subsystem][classid]
+ except KeyError:
+ return "N/A"
+
class Profile(ProfileDict):
- def __init__(self, public_id, updated, data):
- ProfileDict.__init__(self, data)
+ def __init__(self, profile_blob):
+ ProfileDict.__init__(self, profile_blob.get("profile"))
- self.public_id = public_id
- self.updated = updated
+ self.public_id = profile_blob.get("public_id")
+ self.updated = profile_blob.get("updated")
+ self._geoip = profile_blob.get("geoip", None)
def __repr__(self):
return "<%s %s>" % (self.__class__.__name__, self.public_id)
for d in self._data.get("devices"):
d = ProfileDevice(d)
- if d.driver in ("usb", "hub"):
+ if d.driver in ("pcieport", "usb", "hub"):
continue
devices.append(d)
@property
def root_size(self):
- return self.system.get("root_size")
+ return self.system.get("root_size") or 0
+
+ @property
+ def vendor(self):
+ return self.system.get("vendor")
+
+ @property
+ def model(self):
+ return self.system.get("model")
+
+ @property
+ def country_code(self):
+ if self._geoip:
+ return self._geoip["country_code"].lower()
+ return "unknown"
class Stasy(object):
#
# return c
+ def profile_exists(self, public_id):
+ return self._db.profiles.find({ "public_id" : public_id }).count() >= 1
+
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"))
+ p = Profile(p)
return p
return self._db.profiles.distinct("profile.cpu.vendor")
@property
- def cpu_map(self):
+ def cpu_vendors_map(self):
cpus = {}
for vendor in self.cpu_vendors:
return cpus
@property
- def memory_map(self):
+ def cpu_speed_average(self):
+ speed = 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
+ speed += m.get("profile").get("cpu").get("speed")
+
+ return (speed / all.count())
+
+ @property
+ def cpu_speed_map(self):
+ cpu_speeds = {}
+
+ for i in range(len(CPU_SPEED_CONSTRAINTS) - 1):
+ min, max = CPU_SPEED_CONSTRAINTS[i:i+2]
+
+ cpu_speeds[min, max] = \
+ self._db.profiles.find(
+ { "profile.cpu.speed" : {
+ "$gte" : min, "$lt" : max
+ }
+ }).count()
+
+ return cpu_speeds
+
+ def get_memory_map(self):
memory = {}
for i in range(len(MEMORY_CONSTRAINTS) - 1):
def languages(self):
return self._db.profiles.distinct("profile.system.language")
+ def get_language_map(self):
+ languages = {}
+
+ for language in self.languages:
+ languages[language] = \
+ self._db.profiles.find({
+ "profile.system.language" : language
+ }).count()
+
+ return languages
+
@property
def vendors(self):
return self._db.profiles.distinct("profile.system.vendor")
def models(self):
return self._db.profiles.distinct("profile.system.model")
+ @property
+ def model_map(self):
+ models = {}
+
+ for model in self.models:
+ models[model] = \
+ self._db.profiles.find({
+ "profile.system.model" : model
+ }).count()
+
+ return models
+
+ @property
+ def arches(self):
+ return self._db.profiles.distinct("profile.cpu.arch")
+
+ @property
+ def arch_map(self):
+ arches = {}
+
+ for arch in self.arches:
+ arches[arch] = \
+ self._db.profiles.find({
+ "profile.cpu.arch" : arch
+ }).count()
+
+ return arches
+
+ @property
+ def kernels(self):
+ return self._db.profiles.distinct("profile.system.kernel_release")
+
+ @property
+ def kernel_map(self):
+ kernels = {}
+
+ for kernel in self.kernels:
+ kernels[kernel] = \
+ self._db.profiles.find({
+ "profile.system.kernel_release" : kernel
+ }).count()
+
+ return kernels
+
+ @property
+ def releases(self):
+ return self._db.profiles.distinct("profile.system.release")
+
+ @property
+ def release_map(self):
+ releases = {}
+
+ for release in self.releases:
+ releases[release] = \
+ self._db.profiles.find({
+ "profile.system.release" : release
+ }).count()
+
+ return releases
+
+ def get_device_percentage(self, bus, vendor_id, model_id):
+ profiles_with_device = self._db.profiles.find({
+ "profile.devices.subsystem" : bus,
+ "profile.devices.vendor" : vendor_id,
+ "profile.devices.model" : model_id,
+ })
+
+ # XXX must only be systems that have profile data
+ profiles_all = self._db.profiles.find()
+
+ if not profiles_all.count():
+ return 0
+
+ return profiles_with_device.count() / profiles_all.count()
+
+ def get_cpu_flag_map(self, flag):
+ flags = {}
+
+ flags[True] = \
+ self._db.profiles.find({
+ "profile.cpu.flags" : flag,
+ }).count()
+
+ # XXX must only be systems that have profile data
+ profiles_all = self._db.profiles.find()
+
+ flags[False] = profiles_all.count() - flags[True]
+
+ return flags
+
+ @property
+ def geo_locations(self):
+ return [code.lower() for code in self._db.profiles.distinct("geoip.country_code")]
+
+ def get_geo_location_map(self):
+ geo_locations = {}
+
+ count = 0
+ for geo_location in self.geo_locations:
+ geo_locations[geo_location] = \
+ self._db.profiles.find({
+ "geoip.country_code" : geo_location
+ }).count()
+
+ count += geo_locations[geo_location]
+
+ # XXX must only be systems that have profile data
+ profiles_all = self._db.profiles.find()
+
+ unknown_count = profiles_all.count() - count
+ if unknown_count:
+ geo_locations["unknown"] = unknown_count
+
+ return geo_locations
+
+ def get_models_by_vendor(self, subsystem, vendor_id):
+ devices = []
+
+ # XXX must only be systems that have profile data
+ profiles_all = self._db.profiles.find()
+
+ for profile in profiles_all:
+ if not profile.has_key("profile"):
+ continue
+
+ profile = Profile(profile)
+
+ for device in profile.devices:
+ if not device.vendor == vendor_id:
+ continue
+
+ if not device in devices:
+ devices.append(device)
+
+ return devices
if __name__ == "__main__":
print s.hypervisor_vendors
print s.hypervisor_models
print s.languages
+ print s.language_maps
print s.vendors
print s.vendor_map
print s.models
print s.cpus
+ print s.cpu_map
+ print s.arches
+ print s.arch_map
+ print s.kernels
+ print s.kernel_map
+ print s.releases
+ print s.release_map
p = s.get_profile("0b5f4fe2162fdfbfa29b632610e317078fa70d34")
- print p
- print p.hypervisor
+ print p._data
+# print p.hypervisor
+
#!/usr/bin/python
+from __future__ import division
+
+import hwdata
import tornado.web
import backend
def stasy(self):
return backend.Stasy()
+ def format_size(self, s):
+ units = ("K", "M", "G", "T")
+ unit = 0
+
+ while s >= 1024 and unit < len(units):
+ s /= 1024
+ unit += 1
+
+ return "%.1f%s" % (s, units[unit])
+
+ def cut_string(self, s, limit=15):
+ if len(s) > limit:
+ s = s[:limit] + "..."
+
+ return s
+
+ def render(self, *args, **kwargs):
+ kwargs.update({
+ "cut_string" : self.cut_string,
+ "format_size" : self.format_size,
+ })
+
+ return BaseHandler.render(self, *args, **kwargs)
+
class StasyIndexHandler(StasyBaseHandler):
def get(self):
self.render("stasy-index.html", profiles=profiles)
+ def post(self):
+ profile_id = self.get_argument("profile_id", None)
+ if not profile_id:
+ raise tornado.web.HTTPError(400, "No profile ID was given.")
+
+ if not self.stasy.profile_exists(profile_id):
+ raise tornado.web.HTTPError(404, "Profile does not exist.")
-class StasyProfileHandler(StasyBaseHandler):
+ self.redirect("/profile/%s" % profile_id)
+
+
+class StasyProfileDetailHandler(StasyBaseHandler):
def get(self, profile_id):
profile = self.stasy.get_profile(profile_id)
if not profile:
raise tornado.web.HTTPError(404, "Profile not found: %s" % profile_id)
- self.render("stasy-profile.html", profile=profile)
+ self.render("stasy-profile-detail.html", profile=profile)
+
+
+class StasyStatsHandler(StasyBaseHandler):
+ def get(self):
+ self.render("stasy-stats.html")
class StasyStatsCPUHandler(StasyBaseHandler):
def get(self):
return self.render("stasy-stats-cpus.html",
- cpu_vendors = self.stasy.cpu_map)
+ cpu_vendors=self.stasy.cpu_vendors_map,
+ average_speed=self.stasy.cpu_speed_average,
+ cpu_speeds=self.stasy.cpu_speed_map)
+
+
+class StasyStatsCPUFlagsHandler(StasyBaseHandler):
+ def get(self):
+ kwargs = {}
+
+ for flag in ("lm", "pae"):
+ kwargs["cpus_" + flag] = self.stasy.get_cpu_flag_map(flag)
+
+ return self.render("stasy-stats-cpu-flags.html", **kwargs)
+
+class StasyStatsMemoryHandler(StasyBaseHandler):
+ def get(self):
+ return self.render("stasy-stats-memory.html",
+ average_memory=self.stasy.memory_average,
+ memory=self.stasy.get_memory_map())
+
+
+class StasyStatsOSesHandler(StasyBaseHandler):
+ def get(self):
+ return self.render("stasy-stats-oses.html",
+ arches=self.stasy.arch_map,
+ kernels=self.stasy.kernel_map,
+ releases=self.stasy.release_map)
class StasyStatsVirtualHandler(StasyBaseHandler):
return self.render("stasy-stats-virtual.html",
hypervisor_vendors = self.stasy.hypervisor_map,
is_virtual = self.stasy.virtual_map)
+
+class StasyStatsGeoHandler(StasyBaseHandler):
+ def get(self):
+ return self.render("stasy-stats-geo.html",
+ languages = self.stasy.get_language_map(),
+ geo_locations = self.stasy.get_geo_location_map())
+
+
+class StasyStatsVendorDetail(StasyBaseHandler):
+ def get(self, bus, vendor_id):
+ # XXX some way ugly
+ bus2cls = {
+ "pci" : hwdata.PCI,
+ "usb" : hwdata.USB
+ }
+ cls = bus2cls[bus.lower()]
+ vendor_name = cls().get_vendor(vendor_id)
+
+ # Get a list of all models we know from this vendor
+ models = self.stasy.get_models_by_vendor(bus, vendor_id)
+
+ self.render("stasy-vendor-detail.html",
+ vendor_name=vendor_name, models=models)
+
+
+class StasyStatsModelDetail(StasyBaseHandler):
+ def get(self, bus, vendor_id, model_id):
+ bus2cls = {
+ "pci" : hwdata.PCI,
+ "usb" : hwdata.USB
+ }
+
+ cls = bus2cls[bus.lower()]
+
+ vendor_name = cls().get_vendor(vendor_id)
+ model_name = cls().get_device(vendor_id, model_id)
+
+ percentage = \
+ self.stasy.get_device_percentage(bus, vendor_id, model_id) * 100
+
+ self.render("stasy-model-detail.html",
+ vendor_id=vendor_id,
+ vendor_name=vendor_name,
+ model_id=model_id,
+ model_name=model_name,
+ percentage=percentage)
#!/usr/bin/python
+from __future__ import division
+
import logging
+import operator
import socket
import textile
import tornado.escape
from tornado.database import Row
import backend
+import backend.stasy
class UIModule(tornado.web.UIModule):
@property
class StasyTableModule(UIModule):
- def render(self, items):
+ def render(self, items, sortby="key", reverse=False):
hundred_percent = 0
for v in items.values():
hundred_percent += v
+ keys = []
+ if sortby == "key":
+ keys = sorted(items.keys(), reverse=reverse)
+ elif sortby == "percentage":
+ keys = [k for k,v in sorted(items.items(), key=operator.itemgetter(1))]
+ if not reverse:
+ keys = reversed(keys)
+ else:
+ raise Exception, "Unknown sortby parameter was provided"
+
if hundred_percent:
_items = []
- for k in sorted(items.keys()):
- v = float(items[k] * 100) / hundred_percent
+ for k in keys:
+ v = items[k] * 100 / hundred_percent
_items.append((k, v))
items = _items
- print items
-
return self.render_string("modules/stasy-table.html", items=items)
+
+
+class StasyDeviceTableModule(UIModule):
+ def render(self, devices):
+ groups = {}
+
+ for device in devices:
+ if not groups.has_key(device.cls):
+ groups[device.cls] = []
+
+ groups[device.cls].append(device)
+
+ return self.render_string("modules/stasy-table-devices.html",
+ groups=groups.items())