]> git.ipfire.org Git - people/shoehn/ipfire.org.git/blobdiff - www/webapp/backend/stasy.py
Big update of the fireinfo service.
[people/shoehn/ipfire.org.git] / www / webapp / backend / stasy.py
index 6f13a980686942e9a3a1d22e13025be71a952b44..26a241bcf0fa366636091998e897b5a6219cc161 100644 (file)
@@ -1,5 +1,7 @@
 #!/usr/bin/python
 
+from __future__ import division
+
 import hwdata
 import logging
 import pymongo
@@ -9,6 +11,7 @@ from misc import Singleton
 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):
@@ -25,6 +28,14 @@ class ProfileCPU(ProfileDict):
        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")
@@ -37,6 +48,10 @@ class ProfileCPU(ProfileDict):
        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
@@ -58,10 +73,6 @@ class ProfileHypervisor(ProfileDict):
        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")
@@ -73,6 +84,57 @@ class ProfileDevice(ProfileDict):
                "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")
@@ -101,13 +163,32 @@ class ProfileDevice(ProfileDict):
        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)
@@ -122,7 +203,7 @@ class Profile(ProfileDict):
                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)
@@ -156,8 +237,22 @@ class Profile(ProfileDict):
 
        @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):
@@ -181,10 +276,13 @@ 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
 
@@ -210,7 +308,7 @@ class Stasy(object):
                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:
@@ -222,7 +320,36 @@ class Stasy(object):
                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):
@@ -288,6 +415,17 @@ class Stasy(object):
        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")
@@ -308,6 +446,141 @@ class Stasy(object):
        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__":
@@ -327,11 +600,20 @@ 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
+