3 from __future__
import division
11 from misc
import Object
16 "AMDisbetter!" : "AMD",
17 "AuthenticAMD" : "AMD",
18 "CentaurHauls" : "VIA",
19 "CyrixInstead" : "Cyrix",
20 "GenuineIntel" : "Intel",
21 "TransmetaCPU" : "Transmeta",
22 "GenuineTMx86" : "Transmeta",
23 "Geode by NSC" : "NSC",
24 "NexGenDriven" : "NexGen",
25 "RiseRiseRise" : "Rise",
26 "SiS SiS SiS" : "SiS",
27 "SiS SiS SiS " : "SiS",
28 "UMC UMC UMC " : "UMC",
29 "VIA VIA VIA " : "VIA",
30 "Vortex86 SoC" : "Vortex86",
35 (r
"(AMD Athlon).*(XP).*", r
"\1 \2"),
36 (r
"(AMD Phenom).* ([0-9]+) .*", r
"\1 \2"),
37 (r
"(AMD Phenom).*", r
"\1"),
38 (r
"(AMD Sempron).*", r
"\1"),
39 (r
"AMD Athlon.* II X2 ([a-z0-9]+).*", r
"AMD Athlon X2 \1"),
40 (r
"(Geode).*", r
"\1"),
43 (r
"Intel\(R\) (Atom|Celeron).*CPU\s*([A-Z0-9]+) .*", r
"Intel \1 \2"),
44 (r
"(Intel).*(Celeron).*", r
"\1 \2"),
45 (r
"Intel.* Core.*2 Duo *CPU .* ([A-Z0-9]+) .*", r
"Intel C2D \1"),
46 (r
"Intel.* Core.*2 CPU .* ([A-Z0-9]+) .*", r
"Intel C2 \1"),
47 (r
"Intel.* Core.*2 Quad *CPU .* ([A-Z0-9]+) .*", r
"Intel C2Q \1"),
48 (r
"Intel.* Xeon.* CPU .* ([A-Z0-9]+) .*", r
"Intel Xeon \1"),
49 (r
"(Intel).*(Xeon).*", r
"\1 \2"),
50 (r
"Intel.* Pentium.* (D|4) .*", r
"Intel Pentium \1"),
51 (r
"Intel.* Pentium.* Dual .* ([A-Z0-9]+) .*", r
"Intel Pentium Dual \1"),
52 (r
"Pentium.* Dual-Core .* ([A-Z0-9]+) .*", r
"Intel Pentium Dual \1"),
53 (r
"(Pentium I{2,3}).*", r
"Intel \1"),
54 (r
"(Celeron \(Coppermine\))", r
"Intel Celeron"),
57 (r
"(VIA \w*).*", r
"\1"),
60 (r
"QEMU Virtual CPU version .*", r
"QEMU CPU"),
63 (r
"Feroceon .*", r
"ARM Feroceon"),
66 IGNORED_DEVICES
= ["usb",]
68 class ProfileDict(object):
69 def __init__(self
, data
):
73 class ProfileNetwork(ProfileDict
):
74 def __eq__(self
, other
):
78 if not self
.has_red
== other
.has_red
:
81 if not self
.has_green
== other
.has_green
:
84 if not self
.has_orange
== other
.has_orange
:
87 if not self
.has_blue
== other
.has_blue
:
95 for zone
in ("red", "green", "orange", "blue"):
96 if self
.has_zone(zone
):
101 def has_zone(self
, name
):
102 return self
._data
.get("has_%s" % name
)
106 return self
._data
.get("has_red", False)
110 return self
._data
.get("has_green", False)
113 def has_orange(self
):
114 return self
._data
.get("has_orange", False)
118 return self
._data
.get("has_blue", False)
121 class Processor(Object
):
122 def __init__(self
, backend
, id, data
=None, clock_speed
=None, bogomips
=None):
123 Object
.__init
__(self
, backend
)
127 self
.__clock
_speed
= clock_speed
128 self
.__bogomips
= bogomips
133 if not self
.model_string
.startswith(self
.vendor
):
134 s
.append(self
.vendor
)
137 s
.append(self
.model_string
)
139 if self
.core_count
> 1:
140 s
.append("x%s" % self
.core_count
)
146 if self
.__data
is None:
147 self
.__data
= self
.db
.get("SELECT * FROM fireinfo_processors \
148 WHERE id = %s", self
.id)
155 return CPU_VENDORS
[self
.data
.vendor
]
157 return self
.data
.vendor
161 return self
.data
.model
164 def model_string(self
):
165 s
= self
.data
.model_string
.split()
167 return " ".join((e
for e
in s
if e
))
171 return self
.data
.flags
173 def has_flag(self
, flag
):
174 return flag
in self
.flags
177 return self
.has_flag("ht")
180 def core_count(self
):
181 return self
.data
.core_count
186 return self
.core_count
// 2
188 return self
.core_count
191 def clock_speed(self
):
192 return self
.__clock
_speed
194 def format_clock_speed(self
):
195 if not self
.clock_speed
:
198 if self
.clock_speed
< 1000:
199 return "%dMHz" % self
.clock_speed
201 return "%.2fGHz" % round(self
.clock_speed
/ 1000, 2)
205 return self
.__bogomips
208 def capabilities(self
):
210 ("64bit", self
.has_flag("lm")),
211 ("aes", self
.has_flag("aes")),
212 ("nx", self
.has_flag("nx")),
213 ("pae", self
.has_flag("pae") or self
.has_flag("lpae")),
214 ("rdrand", self
.has_flag("rdrand")),
217 # If the system is already running in a virtual environment,
218 # we cannot correctly detect if the CPU supports svm or vmx
219 if self
.has_flag("hypervisor"):
220 caps
.append(("virt", None))
222 caps
.append(("virt", self
.has_flag("vmx") or self
.has_flag("svm")))
226 def format_model(self
):
227 s
= self
.model_string
228 for pattern
, repl
in CPU_STRINGS
:
229 if re
.match(pattern
, s
) is None:
231 return re
.sub(pattern
, repl
, s
)
233 # Otherwise remove the symbols
234 for i
in ("C", "R", "TM"):
235 s
= s
.replace("(%s)" % i
, "")
240 def friendly_string(self
):
243 model
= self
.format_model()
246 clock_speed
= self
.format_clock_speed()
248 s
.append("@ %s" % clock_speed
)
251 s
.append("x%s" % self
.count
)
256 class Device(Object
):
259 "00" : N_("Unclassified"),
260 "01" : N_("Mass storage"),
261 "02" : N_("Network"),
262 "03" : N_("Display"),
263 "04" : N_("Multimedia"),
264 "05" : N_("Memory controller"),
266 "07" : N_("Communication"),
267 "08" : N_("Generic system peripheral"),
268 "09" : N_("Input device"),
269 "0a" : N_("Docking station"),
270 "0b" : N_("Processor"),
271 "0c" : N_("Serial bus"),
272 "0d" : N_("Wireless"),
273 "0e" : N_("Intelligent controller"),
274 "0f" : N_("Satellite communications controller"),
275 "10" : N_("Encryption"),
276 "11" : N_("Signal processing controller"),
277 "ff" : N_("Unassigned class"),
281 "00" : N_("Unclassified"),
282 "01" : N_("Multimedia"),
283 "02" : N_("Communication"),
284 "03" : N_("Input device"),
285 "05" : N_("Generic system peripheral"),
287 "07" : N_("Printer"),
288 "08" : N_("Mass storage"),
290 "0a" : N_("Communication"),
291 "0b" : N_("Smart card"),
292 "0d" : N_("Encryption"),
293 "0e" : N_("Display"),
294 "0f" : N_("Personal Healthcare"),
295 "dc" : N_("Diagnostic Device"),
296 "e0" : N_("Wireless"),
297 "ef" : N_("Unclassified"),
298 "fe" : N_("Unclassified"),
299 "ff" : N_("Unclassified"),
303 def __init__(self
, backend
, id, data
=None):
304 Object
.__init
__(self
, backend
)
310 return "<%s vendor=%s model=%s>" % (self
.__class
__.__name
__,
311 self
.vendor_string
, self
.model_string
)
313 def __cmp__(self
, other
):
314 if self
.id and self
.id == other
.id:
318 cmp(self
.subsystem
, other
.subsystem
) or \
319 cmp(self
.vendor_string
, other
.vendor_string
) or \
320 cmp(self
.vendor
, other
.vendor
) or \
321 cmp(self
.model_string
, other
.model_string
) or \
322 cmp(self
.model
, other
.model
) or \
323 cmp(self
.driver
, other
.driver
)
327 if self
.__data
is None:
330 self
.__data
= self
.db
.get("SELECT * FROM fireinfo_devices \
331 WHERE id = %s", self
.id)
335 def is_showable(self
):
336 if self
.driver
in IGNORED_DEVICES
:
339 if self
.driver
in ("pcieport", "hub"):
346 return self
.data
.subsystem
350 return self
.data
.model
353 def model_string(self
):
354 return self
.fireinfo
.get_model_string(self
.subsystem
,
355 self
.vendor
, self
.model
)
359 return self
.data
.vendor
362 def vendor_string(self
):
363 return self
.fireinfo
.get_vendor_string(self
.subsystem
, self
.vendor
)
367 return self
.data
.driver
371 classid
= self
.data
.deviceclass
373 if self
.subsystem
== "pci":
374 classid
= classid
[:-4]
375 if len(classid
) == 1:
376 classid
= "0%s" % classid
378 elif self
.subsystem
== "usb" and classid
:
379 classid
= classid
.split("/")[0]
380 classid
= "%02x" % int(classid
)
383 return self
.classid2name
[self
.subsystem
][classid
]
388 def percentage(self
):
389 return self
.data
.get("percentage", None)
392 class Profile(Object
):
393 def __init__(self
, backend
, id, data
=None):
394 Object
.__init
__(self
, backend
)
400 return "<%s %s>" % (self
.__class
__.__name
__, self
.public_id
)
402 def __cmp__(self
, other
):
403 return cmp(self
.id, other
.id)
405 def is_showable(self
):
413 if self
.__data
is None:
414 self
.__data
= self
.db
.get("SELECT * FROM fireinfo_profiles \
415 WHERE id = %s", self
.id)
421 return self
.data
.public_id
424 def private_id(self
):
425 raise NotImplementedError
428 def time_created(self
):
429 return self
.data
.time_created
432 def time_updated(self
):
433 return self
.data
.time_updated
435 def updated(self
, profile_parser
=None, location
=None, when
=None):
436 valid
= self
.settings
.get_int("fireinfo_profile_days_valid", 14)
438 self
.db
.execute("UPDATE fireinfo_profiles \
440 time_updated = then_or_now(%s), \
441 time_valid = then_or_now(%s) + INTERVAL '%s days', \
442 updates = updates + 1 \
443 WHERE id = %s", when
, when
, valid
, self
.id)
446 self
.set_processor_speeds(
447 profile_parser
.processor_clock_speed
,
448 profile_parser
.processor_bogomips
,
452 self
.set_location(location
)
454 def expired(self
, when
=None):
455 self
.db
.execute("UPDATE fireinfo_profiles \
456 SET time_valid = then_or_now(%s) WHERE id = %s", when
, self
.id)
458 def parse(self
, parser
):
460 self
.processor
= parser
.processor
461 self
.set_processor_speeds(parser
.processor_clock_speed
, parser
.processor_bogomips
)
464 self
.devices
= parser
.devices
467 self
.system_id
= parser
.system_id
470 self
.memory
= parser
.memory
473 self
.storage
= parser
.storage
476 self
.kernel_id
= parser
.kernel_id
479 self
.arch_id
= parser
.arch_id
482 self
.release_id
= parser
.release_id
485 self
.language
= parser
.language
489 self
.hypervisor_id
= parser
.hypervisor_id
492 self
.network
= parser
.network
496 def get_location(self
):
497 if not hasattr(self
, "_location"):
498 res
= self
.db
.get("SELECT location FROM fireinfo_profiles_locations \
499 WHERE profile_id = %s", self
.id)
502 self
._location
= res
.location
504 self
._location
= None
506 return self
._location
508 def set_location(self
, location
):
509 if self
.location
== location
:
512 self
.db
.execute("DELETE FROM fireinfo_profiles_locations \
513 WHERE profile_id = %s", self
.id)
514 self
.db
.execute("INSERT INTO fireinfo_profiles_locations(profile_id, location) \
515 VALUES(%s, %s)", self
.id, location
)
517 self
._location
= location
519 location
= property(get_location
, set_location
)
522 def location_string(self
):
523 return self
.geoip
.get_country_name(self
.location
)
528 def device_ids(self
):
529 if not hasattr(self
, "_device_ids"):
530 res
= self
.db
.query("SELECT device_id FROM fireinfo_profiles_devices \
531 WHERE profile_id = %s", self
.id)
533 self
._device
_ids
= sorted([r
.device_id
for r
in res
])
535 return self
._device
_ids
537 def get_devices(self
):
538 if not hasattr(self
, "_devices"):
539 res
= self
.db
.query("SELECT * FROM fireinfo_devices \
540 LEFT JOIN fireinfo_profiles_devices ON \
541 fireinfo_devices.id = fireinfo_profiles_devices.device_id \
542 WHERE fireinfo_profiles_devices.profile_id = %s", self
.id)
546 device
= Device(self
.backend
, row
.id, row
)
547 self
._devices
.append(device
)
551 def set_devices(self
, devices
):
552 device_ids
= [d
.id for d
in devices
]
554 self
.db
.execute("DELETE FROM fireinfo_profiles_devices WHERE profile_id = %s", self
.id)
555 self
.db
.executemany("INSERT INTO fireinfo_profiles_devices(profile_id, device_id) \
556 VALUES(%s, %s)", ((self
.id, d
) for d
in device_ids
))
558 self
._devices
= devices
559 self
._device
_ids
= device_ids
561 devices
= property(get_devices
, set_devices
)
563 def count_device(self
, vendor
, model
):
566 for dev
in self
.devices
:
567 if dev
.vendor
== vendor
and dev
.model
== model
:
574 def get_system_id(self
):
575 if not hasattr(self
, "_system_id"):
576 res
= self
.db
.get("SELECT system_id AS id FROM fireinfo_profiles_systems \
577 WHERE profile_id = %s", self
.id)
580 self
._system
_id
= res
.id
582 self
._system
_id
= None
584 return self
._system
_id
586 def set_system_id(self
, system_id
):
587 self
.db
.execute("DELETE FROM fireinfo_profiles_systems WHERE profile_id = %s", self
.id)
590 self
.db
.execute("INSERT INTO fireinfo_profiles_systems(profile_id, system_id) \
591 VALUES(%s, %s)", self
.id, system_id
)
593 self
._system
_id
= None
594 if hasattr(self
, "_system"):
597 system_id
= property(get_system_id
, set_system_id
)
601 if not hasattr(self
, "_system"):
602 res
= self
.db
.get("SELECT fireinfo_systems.vendor AS vendor, fireinfo_systems.model AS model \
603 FROM fireinfo_profiles_systems \
604 LEFT JOIN fireinfo_systems ON fireinfo_profiles_systems.system_id = fireinfo_systems.id \
605 WHERE fireinfo_profiles_systems.profile_id = %s", self
.id)
608 self
._system
= (res
.vendor
, res
.model
)
610 self
._system
= (None, None)
615 def system_vendor(self
):
623 def system_model(self
):
631 def appliance_id(self
):
632 if not hasattr(self
, "_appliance_id"):
634 ("lightningwirelabs-eco", self
._appliance
_test
_lightningwirelabs
_eco
),
637 self
._appliance
_id
= None
638 for name
, test_func
in appliances
:
642 self
._appliance
_id
= name
645 return self
._appliance
_id
649 if self
.appliance_id
== "lightningwirelabs-eco":
650 return "Lightning Wire Labs IPFire Eco Appliance"
652 def _appliance_test_lightningwirelabs_eco(self
):
653 if not self
.system
== ("MSI", "MS-9877"):
656 # Must have four Intel network adapters
657 network_adapters_count
= self
.count_device("8086", "10d3")
658 if not network_adapters_count
== 4:
662 if not self
.memory
>= 4230823936 * 0.95:
670 def processor_id(self
):
671 if hasattr(self
, "_processor"):
672 return self
._processor
.id
674 if not hasattr(self
, "_processor_id"):
675 res
= self
.db
.get("SELECT processor_id FROM fireinfo_profiles_processors \
676 WHERE profile_id = %s", self
.id)
679 self
._processor
_id
= res
.processor_id
681 self
._processor
_id
= None
683 return self
._processor
_id
685 def get_processor(self
):
686 if not self
.processor_id
:
689 if not hasattr(self
, "_processor"):
690 res
= self
.db
.get("SELECT * FROM fireinfo_profiles_processors \
691 WHERE profile_id = %s", self
.id)
694 self
._processor
= self
.fireinfo
.get_processor_by_id(res
.processor_id
,
695 clock_speed
=res
.clock_speed
, bogomips
=res
.bogomips
)
697 self
._processor
= None
699 return self
._processor
701 def set_processor(self
, processor
):
702 self
.db
.execute("DELETE FROM fireinfo_profiles_processors \
703 WHERE profile_id = %s", self
.id)
706 self
.db
.execute("INSERT INTO fireinfo_profiles_processors(profile_id, processor_id) \
707 VALUES(%s, %s)", self
.id, processor
.id)
709 self
._processor
= processor
711 processor
= property(get_processor
, set_processor
)
713 def set_processor_speeds(self
, clock_speed
, bogomips
):
714 self
.db
.execute("UPDATE fireinfo_profiles_processors \
715 SET clock_speed = %s, bogomips = %s WHERE profile_id = %s",
716 clock_speed
, bogomips
, self
.id)
721 return self
.processor
725 def get_memory(self
):
726 if not hasattr(self
, "_memory"):
727 res
= self
.db
.get("SELECT amount FROM fireinfo_profiles_memory \
728 WHERE profile_id = %s", self
.id)
731 self
._memory
= res
.amount
* 1024
737 def set_memory(self
, amount
):
738 if self
.memory
== amount
:
743 self
.db
.execute("DELETE FROM fireinfo_profiles_memory WHERE profile_id = %s", self
.id)
745 self
.db
.execute("INSERT INTO fireinfo_profiles_memory(profile_id, amount) \
746 VALUES(%s, %s)", self
.id, amount
)
748 self
._memory
= amount
* 1024
750 memory
= property(get_memory
, set_memory
)
753 def friendly_memory(self
):
754 return util
.format_size(self
.memory
)
758 def get_storage(self
):
759 if not hasattr(self
, "_storage"):
760 res
= self
.db
.get("SELECT amount FROM fireinfo_profiles_storage \
761 WHERE profile_id = %s", self
.id)
764 self
._storage
= res
.amount
* 1024
770 def set_storage(self
, amount
):
771 if self
.storage
== amount
:
776 self
.db
.execute("DELETE FROM fireinfo_profiles_storage WHERE profile_id = %s", self
.id)
778 self
.db
.execute("INSERT INTO fireinfo_profiles_storage(profile_id, amount) \
779 VALUES(%s, %s)", self
.id, amount
)
781 self
._storage
= amount
* 1024
783 storage
= property(get_storage
, set_storage
)
786 def friendly_storage(self
):
787 return util
.format_size(self
.storage
)
791 def get_kernel_id(self
):
792 if not hasattr(self
, "_kernel_id"):
793 res
= self
.db
.get("SELECT fireinfo_profiles_kernels.kernel_id AS id FROM fireinfo_profiles \
794 LEFT JOIN fireinfo_profiles_kernels ON fireinfo_profiles.id = fireinfo_profiles_kernels.profile_id \
795 WHERE fireinfo_profiles.id = %s", self
.id)
798 self
._kernel
_id
= res
.id
800 self
._kernel
_id
= None
802 return self
._kernel
_id
804 def set_kernel_id(self
, kernel_id
):
805 if self
.kernel_id
== kernel_id
:
808 self
.db
.execute("DELETE FROM fireinfo_profiles_kernels WHERE profile_id = %s", self
.id)
810 self
.db
.execute("INSERT INTO fireinfo_profiles_kernels(profile_id, kernel_id) \
811 VALUES(%s, %s)", self
.id, kernel_id
)
813 self
._kernel
_id
= kernel_id
814 if hasattr(self
, "_kernel"):
817 kernel_id
= property(get_kernel_id
, set_kernel_id
)
821 if not hasattr(self
, "_kernel"):
822 res
= self
.db
.get("SELECT fireinfo_kernels.name AS name FROM fireinfo_profiles \
823 LEFT JOIN fireinfo_profiles_kernels ON fireinfo_profiles.id = fireinfo_profiles_kernels.profile_id \
824 LEFT JOIN fireinfo_kernels ON fireinfo_kernels.id = fireinfo_profiles_kernels.kernel_id \
825 WHERE fireinfo_profiles.id = %s", self
.id)
828 self
._kernel
= res
.name
836 def get_arch_id(self
):
837 if not hasattr(self
, "_arch_id"):
838 res
= self
.db
.get("SELECT fireinfo_profiles_arches.arch_id AS id FROM fireinfo_profiles \
839 LEFT JOIN fireinfo_profiles_arches ON fireinfo_profiles.id = fireinfo_profiles_arches.profile_id \
840 WHERE fireinfo_profiles.id = %s", self
.id)
843 self
._arch
_id
= res
.id
849 def set_arch_id(self
, arch_id
):
850 if self
.arch_id
== arch_id
:
853 self
.db
.execute("DELETE FROM fireinfo_profiles_arches WHERE profile_id = %s", self
.id)
855 self
.db
.execute("INSERT INTO fireinfo_profiles_arches(profile_id, arch_id) \
856 VALUES(%s, %s)", self
.id, arch_id
)
859 if hasattr(self
, "_arch"):
862 arch_id
= property(get_arch_id
, set_arch_id
)
866 if not hasattr(self
, "_arch"):
867 res
= self
.db
.get("SELECT fireinfo_arches.name AS name FROM fireinfo_profiles \
868 LEFT JOIN fireinfo_profiles_arches ON fireinfo_profiles.id = fireinfo_profiles_arches.profile_id \
869 LEFT JOIN fireinfo_arches ON fireinfo_arches.id = fireinfo_profiles_arches.arch_id \
870 WHERE fireinfo_profiles.id = %s", self
.id)
873 self
._arch
= res
.name
881 def get_release_id(self
):
882 if not hasattr(self
, "_release_id"):
883 res
= self
.db
.get("SELECT fireinfo_profiles_releases.release_id AS id FROM fireinfo_profiles \
884 LEFT JOIN fireinfo_profiles_releases ON fireinfo_profiles.id = fireinfo_profiles_releases.profile_id \
885 WHERE fireinfo_profiles.id = %s", self
.id)
888 self
._release
_id
= res
.id
890 self
._release
_id
= None
892 return self
._release
_id
894 def set_release_id(self
, release_id
):
895 if self
.release_id
== release_id
:
898 self
.db
.execute("DELETE FROM fireinfo_profiles_releases WHERE profile_id = %s", self
.id)
900 self
.db
.execute("INSERT INTO fireinfo_profiles_releases(profile_id, release_id) \
901 VALUES(%s, %s)", self
.id, release_id
)
903 self
._release
_id
= release_id
904 if hasattr(self
, "_release"):
907 release_id
= property(get_release_id
, set_release_id
)
911 if not hasattr(self
, "_release"):
912 res
= self
.db
.get("SELECT fireinfo_releases.name AS name FROM fireinfo_profiles \
913 LEFT JOIN fireinfo_profiles_releases ON fireinfo_profiles.id = fireinfo_profiles_releases.profile_id \
914 LEFT JOIN fireinfo_releases ON fireinfo_profiles_releases.release_id = fireinfo_releases.id \
915 WHERE fireinfo_profiles.id = %s", self
.id)
918 self
._release
= self
._format
_release
(res
.name
)
925 def _format_release(r
):
929 # Remove the development header
930 r
= r
.replace("Development Build: ", "")
933 ("-beta", " - Beta "),
934 ("-rc", " - Release Candidate "),
935 ("rc", "Release Candidate "),
936 ("core", "Core Update "),
949 if not hasattr(self
, "_virtual"):
950 res
= self
.db
.get("SELECT 1 FROM fireinfo_profiles_virtual \
951 WHERE profile_id = %s", self
.id)
956 self
._virtual
= False
960 def get_hypervisor_id(self
):
961 if not hasattr(self
, "_hypervisor_id"):
962 res
= self
.db
.get("SELECT fireinfo_profiles_virtual.hypervisor_id AS id FROM fireinfo_profiles \
963 LEFT JOIN fireinfo_profiles_virtual ON fireinfo_profiles.id = fireinfo_profiles_virtual.profile_id \
964 WHERE fireinfo_profiles.id = %s", self
.id)
967 self
._hypervisor
_id
= res
.id
969 self
._hypervisor
_id
= None
971 return self
._hypervisor
_id
973 def set_hypervisor_id(self
, hypervisor_id
):
974 self
.db
.execute("DELETE FROM fireinfo_profiles_virtual WHERE profile_id = %s", self
.id)
975 self
.db
.execute("INSERT INTO fireinfo_profiles_virtual(profile_id, hypervisor_id) \
976 VALUES(%s, %s)", self
.id, hypervisor_id
)
978 self
._hypervisor
_id
= hypervisor_id
980 hypervisor_id
= property(get_hypervisor_id
, set_hypervisor_id
)
983 def hypervisor(self
):
984 if not hasattr(self
, "_hypervisor"):
985 res
= self
.db
.get("SELECT fireinfo_hypervisors.name AS hypervisor FROM fireinfo_profiles \
986 LEFT JOIN fireinfo_profiles_virtual ON fireinfo_profiles.id = fireinfo_profiles_virtual.profile_id \
987 LEFT JOIN fireinfo_hypervisors ON fireinfo_profiles_virtual.hypervisor_id = fireinfo_hypervisors.id \
988 WHERE fireinfo_profiles.id = %s", self
.id)
991 self
._hypervisor
= res
.hypervisor
993 self
._hypervisor
= None
995 return self
._hypervisor
999 def get_language(self
):
1000 if not hasattr(self
, "_language"):
1001 res
= self
.db
.get("SELECT language FROM fireinfo_profiles_languages \
1002 WHERE profile_id = %s", self
.id)
1005 self
._language
= res
.language
1007 self
._language
= None
1009 return self
._language
1011 def set_language(self
, language
):
1012 self
.db
.execute("DELETE FROM fireinfo_profiles_languages WHERE profile_id = %s", self
.id)
1015 self
.db
.execute("INSERT INTO fireinfo_profiles_languages(profile_id, language) \
1016 VALUES(%s, %s)", self
.id, language
)
1018 self
._language
= language
1020 language
= property(get_language
, set_language
)
1024 def get_network(self
):
1025 if not hasattr(self
, "_network"):
1026 res
= self
.db
.get("SELECT * FROM fireinfo_profiles_networks \
1027 WHERE profile_id = %s", self
.id)
1032 self
._network
= ProfileNetwork(res
)
1034 return self
._network
1036 def set_network(self
, network
):
1037 self
.db
.execute("DELETE FROM fireinfo_profiles_networks WHERE profile_id = %s", self
.id)
1040 self
.db
.execute("INSERT INTO fireinfo_profiles_networks(profile_id, \
1041 has_red, has_green, has_orange, has_blue) VALUES(%s, %s, %s, %s, %s)",
1042 self
.id, network
.has_red
, network
.has_green
, network
.has_orange
, network
.has_blue
)
1044 self
._network
= network
1046 network
= property(get_network
, set_network
)
1049 class ProfileData(Object
):
1050 def __init__(self
, backend
, id, data
=None, profile
=None):
1051 Object
.__init
__(self
, backend
)
1055 self
._profile
= profile
1059 if self
._data
is None:
1060 self
._data
= self
.db
.get("SELECT * FROM fireinfo_profile_data \
1061 WHERE id = %s", self
.id)
1067 if not self
._profile
:
1068 self
._profile
= self
.fireinfo
.get_profile_by_id(self
.profile_id
)
1070 return self
._profile
1073 def profile_id(self
):
1074 return self
.data
.profile_id
1077 class ProfileParserError(Exception):
1081 class ProfileParser(Object
):
1092 __processor_args
= (
1102 __processor_args_mandatory
= (
1107 def __init__(self
, backend
, public_id
, blob
=None):
1108 Object
.__init
__(self
, backend
)
1110 self
.public_id
= public_id
1111 self
.private_id
= None
1113 self
.processor
= None
1114 self
.processor_clock_speed
= None
1115 self
.processor_bogomips
= None
1116 self
.system_id
= None
1120 self
.kernel_id
= None
1124 self
.release_id
= None
1125 self
.language
= None
1127 self
.hypervisor_id
= None
1130 self
.__parse
_blob
(blob
)
1132 def equals(self
, other
):
1133 if not self
.processor_id
== other
.processor_id
:
1136 if not self
.device_ids
== other
.device_ids
:
1139 if not self
.system_id
== other
.system_id
:
1142 if not self
.memory
== other
.memory
:
1145 if not self
.storage
== other
.storage
:
1148 if not self
.kernel_id
== other
.kernel_id
:
1151 if not self
.arch_id
== other
.arch_id
:
1154 if not self
.release_id
== other
.release_id
:
1157 if not self
.language
== other
.language
:
1160 if not self
.virtual
== other
.virtual
:
1164 if not self
.hypervisor_id
== other
.hypervisor_id
:
1167 if not self
.network
== other
.network
:
1172 def __parse_blob(self
, blob
):
1173 _profile
= blob
.get("profile", {})
1174 self
.private_id
= blob
.get("private_id")
1176 # Do not try to parse an empty profile
1181 _processor
= _profile
.get("cpu", {})
1182 self
.__parse
_processor
(_processor
)
1185 _devices
= _profile
.get("devices", [])
1186 self
.__parse
_devices
(_devices
)
1189 _system
= _profile
.get("system")
1191 self
.__parse
_system
(_system
)
1193 # Memory (convert to bytes)
1194 memory
= _system
.get("memory", None)
1196 self
.memory
= memory
* 1024
1198 # Storage size (convert to bytes)
1199 storage
= _system
.get("root_size", None)
1201 self
.storage
= storage
* 1024
1204 kernel
= _system
.get("kernel_release", None)
1206 self
.__parse
_kernel
(kernel
)
1209 release
= _system
.get("release", None)
1211 self
.__parse
_release
(release
)
1214 language
= _system
.get("language", None)
1216 self
.__parse
_language
(language
)
1219 self
.virtual
= _system
.get("virtual", False)
1221 hypervisor
= _profile
.get("hypervisor")
1222 self
.__parse
_hypervisor
(hypervisor
)
1225 _network
= _profile
.get("network")
1227 self
.__parse
_network
(_network
)
1230 def device_ids(self
):
1231 return sorted([d
.id for d
in self
.devices
])
1233 def __parse_devices(self
, _devices
):
1236 for _device
in _devices
:
1238 for arg
in self
.__device
_args
:
1239 args
[arg
] = _device
.get(arg
, None)
1241 # Skip if the subsystem is not set
1242 if not args
.get("subsystem", None):
1245 # Find the device or create a new one.
1246 device
= self
.fireinfo
.get_device(**args
)
1248 device
= self
.fireinfo
.create_device(**args
)
1250 self
.devices
.append(device
)
1252 def __parse_system(self
, system
):
1253 vendor
= system
.get("vendor", None)
1257 model
= system
.get("model", None)
1261 self
.system_id
= self
.fireinfo
.get_system(vendor
, model
)
1262 if not self
.system_id
:
1263 self
.system_id
= self
.fireinfo
.create_system(vendor
, model
)
1266 def processor_id(self
):
1267 if not self
.processor
:
1270 return self
.processor
.id
1272 def __parse_processor(self
, _processor
):
1274 for arg
in self
.__processor
_args
:
1275 if arg
== "core_count":
1280 args
[arg
] = _processor
.get(_arg
, None)
1282 for arg
in self
.__processor
_args
_mandatory
:
1283 if not args
.get(arg
, None):
1284 raise ProfileParserError
, "Mandatory argument missing: %s" % arg
1286 self
.processor
= self
.fireinfo
.get_processor(**args
)
1287 if not self
.processor
:
1288 self
.processor
= self
.fireinfo
.create_processor(**args
)
1290 self
.processor_clock_speed
= _processor
.get("speed", None)
1291 self
.processor_bogomips
= _processor
.get("bogomips", None)
1293 arch
= _processor
.get("arch", None)
1295 self
.__parse
_arch
(arch
)
1297 def __parse_kernel(self
, kernel
):
1298 self
.kernel_id
= self
.fireinfo
.get_kernel(kernel
)
1299 if not self
.kernel_id
:
1300 self
.kernel_id
= self
.fireinfo
.create_kernel(kernel
)
1301 assert self
.kernel_id
1303 self
.kernel
= kernel
1305 def __parse_arch(self
, arch
):
1306 self
.arch_id
= self
.fireinfo
.get_arch(arch
)
1307 if not self
.arch_id
:
1308 self
.arch_id
= self
.fireinfo
.create_arch(arch
)
1312 def __parse_release(self
, release
):
1313 # Remove the arch bit
1315 r
= [e
for e
in release
.split() if e
]
1316 for s
in ("(i586)", "(armv5tel)"):
1323 release
= " ".join(r
)
1325 self
.release_id
= self
.fireinfo
.get_release(release
)
1326 if not self
.release_id
:
1327 self
.release_id
= self
.fireinfo
.create_release(release
)
1328 assert self
.release_id
1330 self
.release
= release
1332 def __parse_language(self
, language
):
1333 self
.language
, delim
, rest
= language
.partition(".")
1334 self
.language
, delim
, rest
= language
.partition("_")
1336 def __parse_hypervisor(self
, hypervisor
):
1337 vendor
= hypervisor
.get("vendor", "other")
1339 if vendor
in ("other", "unknown"):
1340 self
.hypervisor_id
= None
1343 self
.hypervisor_id
= self
.fireinfo
.get_hypervisor(vendor
)
1344 if not self
.hypervisor_id
:
1345 self
.hypervisor_id
= self
.fireinfo
.create_hypervisor(vendor
)
1347 def __parse_network(self
, network
):
1348 self
.network
= ProfileNetwork({
1349 "has_red" : network
.get("red", False),
1350 "has_green" : network
.get("green", False),
1351 "has_orange" : network
.get("orange", False),
1352 "has_blue" : network
.get("blue", False),
1356 class Fireinfo(Object
):
1357 def get_profile_count(self
, when
=None):
1358 res
= self
.db
.get("SELECT COUNT(*) AS count FROM fireinfo_profiles \
1359 WHERE then_or_now(%s) BETWEEN time_created AND time_valid", when
)
1364 def get_archives_count(self
):
1365 res
= self
.db
.get("SELECT COUNT(*) AS count FROM fireinfo_profiles")
1372 def parse_profile(self
, public_id
, blob
):
1373 return ProfileParser(self
.backend
, public_id
, blob
)
1377 def profile_exists(self
, public_id
):
1378 res
= self
.db
.get("SELECT id FROM fireinfo_profiles \
1379 WHERE public_id = %s LIMIT 1", public_id
)
1386 def can_update_profile(self
, public_id
, private_id
, when
=None):
1387 res
= self
.db
.get("SELECT 1 FROM fireinfo_profiles \
1388 WHERE public_id = %s AND private_id = %s \
1389 AND time_updated + INTERVAL '60 minutes' <= then_or_now(%s) \
1390 AND time_valid >= then_or_now(%s) ORDER BY time_updated DESC LIMIT 1",
1391 public_id
, private_id
, when
, when
)
1398 def get_profile(self
, public_id
, private_id
=None, when
=None):
1399 res
= self
.db
.get("SELECT * FROM fireinfo_profiles \
1400 WHERE public_id = %s AND \
1401 (CASE WHEN %s IS NULL THEN TRUE ELSE private_id = %s END) AND \
1402 (CASE WHEN %s IS NULL THEN TRUE ELSE \
1403 then_or_now(%s) BETWEEN time_created AND time_valid END) \
1404 ORDER BY time_updated DESC LIMIT 1", public_id
,
1405 private_id
, private_id
, when
, when
)
1408 return Profile(self
.backend
, res
.id, res
)
1410 def get_profiles(self
, public_id
):
1411 res
= self
.db
.query("SELECT * FROM fireinfo_profiles \
1412 WHERE public_id = %s ORDER BY time_created DESC", public_id
)
1416 profile
= Profile(self
.backend
, row
.id, row
)
1417 profiles
.append(profile
)
1421 def create_profile(self
, public_id
, private_id
, when
=None):
1422 valid
= self
.settings
.get_int("fireinfo_profile_days_valid", 14)
1424 res
= self
.db
.get("INSERT INTO fireinfo_profiles(public_id, private_id, \
1425 time_created, time_updated, time_valid) VALUES(%s, %s, then_or_now(%s), \
1426 then_or_now(%s), then_or_now(%s) + INTERVAL '%s days') RETURNING id",
1427 public_id
, private_id
, when
, when
, when
, valid
)
1430 return Profile(self
.backend
, res
.id)
1434 def create_device(self
, subsystem
, vendor
, model
, sub_vendor
=None, sub_model
=None,
1435 driver
=None, deviceclass
=None):
1436 res
= self
.db
.get("INSERT INTO fireinfo_devices(subsystem, vendor, model, \
1437 sub_vendor, sub_model, driver, deviceclass) VALUES(%s, %s, %s, %s, %s, %s, %s) \
1438 RETURNING id", subsystem
, vendor
, model
, sub_vendor
, sub_model
, driver
, deviceclass
)
1441 return Device(self
.backend
, res
.id)
1443 def get_device(self
, subsystem
, vendor
, model
, sub_vendor
=None, sub_model
=None,
1444 driver
=None, deviceclass
=None):
1445 res
= self
.db
.get("SELECT * FROM fireinfo_devices \
1446 WHERE subsystem = %s AND vendor = %s AND model = %s \
1447 AND sub_vendor IS NOT DISTINCT FROM %s \
1448 AND sub_model IS NOT DISTINCT FROM %s \
1449 AND driver IS NOT DISTINCT FROM %s \
1450 AND deviceclass IS NOT DISTINCT FROM %s \
1451 LIMIT 1", subsystem
, vendor
, model
, sub_vendor
,
1452 sub_model
, driver
, deviceclass
)
1455 return Device(self
.backend
, res
.id, res
)
1459 def create_system(self
, vendor
, model
):
1460 res
= self
.db
.get("INSERT INTO fireinfo_systems(vendor, model) \
1461 VALUES(%s, %s) RETURNING id", vendor
, model
)
1466 def get_system(self
, vendor
, model
):
1467 res
= self
.db
.get("SELECT id FROM fireinfo_systems WHERE vendor IS NOT DISTINCT FROM %s \
1468 AND model IS NOT DISTINCT FROM %s LIMIT 1", vendor
, model
)
1475 def create_processor(self
, vendor
, model_string
, family
, model
, stepping
, core_count
, flags
=None):
1476 res
= self
.db
.get("INSERT INTO fireinfo_processors(vendor, model_string, \
1477 family, model, stepping, core_count, flags) VALUES(%s, %s, %s, %s, %s, %s, %s) \
1478 RETURNING id", vendor
, model_string
, family
, model
, stepping
, core_count
, flags
)
1481 return Processor(self
.backend
, res
.id)
1483 def get_processor_by_id(self
, processor_id
, **kwargs
):
1484 res
= self
.db
.get("SELECT * FROM fireinfo_processors \
1485 WHERE id = %s", processor_id
)
1488 return Processor(self
.backend
, res
.id, data
=res
, **kwargs
)
1490 def get_processor(self
, vendor
, model_string
, family
, model
, stepping
, core_count
, flags
=None):
1494 res
= self
.db
.get("SELECT * FROM fireinfo_processors \
1495 WHERE vendor = %s AND model_string = %s \
1496 AND family IS NOT DISTINCT FROM %s AND model IS NOT DISTINCT FROM %s \
1497 AND stepping IS NOT DISTINCT FROM %s AND core_count = %s \
1498 AND flags <@ %s AND flags @> %s", vendor
, model_string
, family
, model
,
1499 stepping
, core_count
, flags
, flags
)
1502 return Processor(self
.backend
, res
.id, res
)
1506 def create_kernel(self
, kernel
):
1507 res
= self
.db
.get("INSERT INTO fireinfo_kernels(name) VALUES(%s) \
1508 RETURNING id", kernel
)
1513 def get_kernel(self
, kernel
):
1514 res
= self
.db
.get("SELECT id FROM fireinfo_kernels WHERE name = %s", kernel
)
1521 def create_arch(self
, arch
):
1522 res
= self
.db
.get("INSERT INTO fireinfo_arches(name) VALUES(%s) \
1523 RETURNING id", arch
)
1528 def get_arch(self
, arch
):
1529 res
= self
.db
.get("SELECT id FROM fireinfo_arches WHERE name = %s", arch
)
1536 def create_release(self
, release
):
1537 res
= self
.db
.get("INSERT INTO fireinfo_releases(name) VALUES(%s) \
1538 RETURNING id", release
)
1543 def get_release(self
, release
):
1544 res
= self
.db
.get("SELECT id FROM fireinfo_releases WHERE name = %s", release
)
1551 def create_hypervisor(self
, hypervisor
):
1552 res
= self
.db
.get("INSERT INTO fireinfo_hypervisors(name) VALUES(%s) \
1553 RETURNING id", hypervisor
)
1558 def get_hypervisor(self
, hypervisor
):
1559 res
= self
.db
.get("SELECT id FROM fireinfo_hypervisors WHERE name = %s",
1567 def handle_profile(self
, *args
, **kwargs
):
1568 self
.db
.execute("START TRANSACTION")
1570 # Wrap all the handling of the profile in a huge transaction.
1572 self
._handle
_profile
(*args
, **kwargs
)
1575 self
.db
.execute("ROLLBACK")
1579 self
.db
.execute("COMMIT")
1581 def _handle_profile(self
, public_id
, profile_blob
, location
=None, when
=None):
1582 private_id
= profile_blob
.get("private_id", None)
1585 # Check if the profile already exists in the database.
1586 profile
= self
.fireinfo
.get_profile(public_id
, private_id
=private_id
, when
=when
)
1588 # Check if the update can actually be updated
1589 if profile
and not self
.fireinfo
.can_update_profile(public_id
, private_id
, when
=when
):
1590 logging
.warning("Profile not updated because private ID does not"
1591 " match or last update is too recent: %s" % public_id
)
1595 profile_parser
= self
.parse_profile(public_id
, profile_blob
)
1597 # If a profile exists, check if it matches and if so, just update the
1600 # Check if the profile has changed. If so, update the data.
1601 if profile_parser
.equals(profile
):
1602 profile
.updated(profile_parser
, location
=location
, when
=when
)
1605 # If it does not match, we assume that it is expired and
1606 # create a new profile.
1607 profile
.expired(when
=when
)
1609 # Replace the old profile with a new one
1610 profile
= self
.fireinfo
.create_profile(public_id
, private_id
, when
=when
)
1611 profile
.parse(profile_parser
)
1614 profile
.set_location(location
)
1620 def get_random_profile(self
, when
=None):
1621 # Check if the architecture exists so that we pick a profile with some data
1622 res
= self
.db
.get("SELECT public_id FROM fireinfo_profiles \
1623 LEFT JOIN fireinfo_profiles_arches ON fireinfo_profiles.id = fireinfo_profiles_arches.profile_id \
1624 WHERE fireinfo_profiles_arches.profile_id IS NOT NULL \
1625 AND then_or_now(%s) BETWEEN time_created AND time_valid ORDER BY RANDOM() LIMIT 1", when
)
1628 return res
.public_id
1630 def get_active_profiles(self
, when
=None):
1631 res
= self
.db
.get("WITH profiles AS (SELECT fireinfo_profiles_at(%s) AS id) \
1632 SELECT COUNT(*) AS with_data, (SELECT COUNT(*) FROM profiles) AS count FROM profiles \
1633 LEFT JOIN fireinfo_profiles_releases ON profiles.id = fireinfo_profiles_releases.profile_id \
1634 WHERE fireinfo_profiles_releases.profile_id IS NOT NULL", when
)
1637 return res
.with_data
, res
.count
1639 def get_archive_size(self
, when
=None):
1640 res
= self
.db
.get("SELECT COUNT(*) AS count FROM fireinfo_profiles \
1641 WHERE time_created <= then_or_now(%s)", when
)
1646 def get_geo_location_map(self
, when
=None):
1647 res
= self
.db
.query("WITH profiles AS (SELECT fireinfo_profiles_at(%s) AS id) \
1648 SELECT location, COUNT(location)::float / (SELECT COUNT(*) FROM profiles) AS count FROM profiles \
1649 LEFT JOIN fireinfo_profiles_locations ON profiles.id = fireinfo_profiles_locations.profile_id \
1650 WHERE fireinfo_profiles_locations.location IS NOT NULL GROUP BY location ORDER BY count DESC", when
)
1652 return ((r
.location
, r
.count
) for r
in res
)
1654 def get_language_map(self
, when
=None):
1655 res
= self
.db
.query("WITH profiles AS (SELECT fireinfo_profiles_at(%s) AS id) \
1656 SELECT language, COUNT(language)::float / (SELECT COUNT(*) FROM profiles) AS count FROM profiles \
1657 LEFT JOIN fireinfo_profiles_languages ON profiles.id = fireinfo_profiles_languages.profile_id \
1658 WHERE fireinfo_profiles_languages.language IS NOT NULL GROUP BY language ORDER BY count DESC", when
)
1660 return ((r
.language
, r
.count
) for r
in res
)
1663 def cpu_vendors(self
):
1664 res
= self
.db
.query("SELECT DISTINCT vendor FROM fireinfo_processors ORDER BY vendor")
1666 return (CPU_VENDORS
.get(r
.vendor
, r
.vendor
) for r
in res
)
1668 def get_cpu_vendors_map(self
, when
=None):
1669 res
= self
.db
.query("WITH profiles AS (SELECT fireinfo_profiles_with_data_at(%s) AS id) \
1670 SELECT vendor, COUNT(vendor)::float / (SELECT COUNT(*) FROM profiles) AS count FROM profiles \
1671 LEFT JOIN fireinfo_profiles_processors ON profiles.id = fireinfo_profiles_processors.profile_id \
1672 LEFT JOIN fireinfo_processors ON fireinfo_profiles_processors.processor_id = fireinfo_processors.id \
1673 WHERE NOT fireinfo_profiles_processors.processor_id IS NULL GROUP BY vendor ORDER BY count DESC", when
)
1675 return ((CPU_VENDORS
.get(r
.vendor
, r
.vendor
), r
.count
) for r
in res
)
1677 def get_cpu_clock_speeds(self
, when
=None):
1678 res
= self
.db
.get("WITH profiles AS (SELECT fireinfo_profiles_with_data_at(%s) AS id) \
1679 SELECT AVG(fireinfo_profiles_processors.clock_speed) AS avg, \
1680 STDDEV(fireinfo_profiles_processors.clock_speed) AS stddev, \
1681 MIN(fireinfo_profiles_processors.clock_speed) AS min, \
1682 MAX(fireinfo_profiles_processors.clock_speed) AS max FROM profiles \
1683 LEFT JOIN fireinfo_profiles_processors ON profiles.id = fireinfo_profiles_processors.profile_id \
1684 WHERE NOT fireinfo_profiles_processors.processor_id IS NULL \
1685 AND fireinfo_profiles_processors.clock_speed > 0", when
)
1688 return (res
.avg
or 0, res
.stddev
or 0, res
.min or 0, res
.max or 0)
1690 def get_cpus_with_platform_and_flag(self
, platform
, flag
, when
=None):
1691 res
= self
.db
.get("WITH profiles AS (SELECT fireinfo_profiles_with_data_at(%s) AS id), \
1692 processors AS (SELECT fireinfo_processors.id AS id, fireinfo_processors.flags AS flags FROM profiles \
1693 LEFT JOIN fireinfo_profiles_processors ON profiles.id = fireinfo_profiles_processors.profile_id \
1694 LEFT JOIN fireinfo_processors ON fireinfo_profiles_processors.processor_id = fireinfo_processors.id \
1695 LEFT JOIN fireinfo_profiles_arches ON profiles.id = fireinfo_profiles_arches.profile_id \
1696 LEFT JOIN fireinfo_arches ON fireinfo_profiles_arches.arch_id = fireinfo_arches.id \
1697 WHERE NOT fireinfo_profiles_processors.processor_id IS NULL \
1698 AND fireinfo_arches.platform = %s AND NOT 'hypervisor' = ANY(fireinfo_processors.flags)) \
1699 SELECT (COUNT(*)::float / (SELECT NULLIF(COUNT(*), 0) FROM processors)) AS count FROM processors \
1700 WHERE %s = ANY(processors.flags)", when
, platform
, flag
)
1702 return res
.count
or 0
1704 def get_common_cpu_flags_by_platform(self
, platform
, when
=None):
1705 if platform
== "arm":
1707 "lpae", "neon", "thumb", "thumb2", "thumbee", "vfpv3", "vfpv4",
1709 elif platform
== "x86":
1711 "aes", "avx", "avx2", "lm", "mmx", "mmxext", "nx", "pae",
1712 "pni", "popcnt", "sse", "sse2", "rdrand", "ssse3", "sse4a",
1720 ret
.append((flag
, self
.get_cpus_with_platform_and_flag(platform
, flag
, when
=when
)))
1722 # Add virtual CPU flag "virt" for virtualization support
1723 if platform
== "x86":
1725 self
.get_cpus_with_platform_and_flag(platform
, "vmx", when
=when
) + \
1726 self
.get_cpus_with_platform_and_flag(platform
, "svm", when
=when
)))
1728 return sorted(ret
, key
=lambda x
: x
[1], reverse
=True)
1730 def get_common_memory_amounts(self
, when
=None):
1731 amounts
= (128, 256, 512, 1024, 2 * 1024, 4 * 1024, 8 * 1024, 16 * 1024, 32 * 1024, 64 * 1024)
1734 for amount
in amounts
:
1735 ret
.append((amount
, self
.get_memory_amount(amount
* 1024 * 0.95, when
=when
)))
1739 def get_memory_amount(self
, greather_than
, when
=None):
1740 res
= self
.db
.get("WITH profiles AS (SELECT fireinfo_profiles_with_data_at(%s) AS id) \
1741 SELECT COUNT(*)::float / (SELECT COUNT(*) FROM profiles \
1742 LEFT JOIN fireinfo_profiles_memory ON profiles.id = fireinfo_profiles_memory.profile_id \
1743 WHERE NOT fireinfo_profiles_memory.amount IS NULL) AS percentage FROM profiles \
1744 LEFT JOIN fireinfo_profiles_memory ON profiles.id = fireinfo_profiles_memory.profile_id \
1745 WHERE fireinfo_profiles_memory.amount >= %s", when
, greather_than
)
1748 return res
.percentage
1750 def get_memory_amounts(self
, when
=None):
1751 res
= self
.db
.get("WITH profiles AS (SELECT fireinfo_profiles_with_data_at(%s) AS id) \
1752 SELECT AVG(fireinfo_profiles_memory.amount) AS avg, \
1753 STDDEV(fireinfo_profiles_memory.amount) AS stddev, \
1754 MIN(fireinfo_profiles_memory.amount) AS min, \
1755 MAX(fireinfo_profiles_memory.amount) AS max FROM profiles \
1756 LEFT JOIN fireinfo_profiles_memory ON profiles.id = fireinfo_profiles_memory.profile_id", when
)
1759 return (res
.avg
or 0, res
.stddev
or 0, res
.min or 0, res
.max or 0)
1761 def get_arch_map(self
, when
=None):
1762 res
= self
.db
.query("WITH profiles AS (SELECT fireinfo_profiles_with_data_at(%s) AS id) \
1763 SELECT fireinfo_arches.name AS arch, COUNT(*)::float / (SELECT COUNT(*) FROM profiles) AS count \
1765 LEFT JOIN fireinfo_profiles_arches ON profiles.id = fireinfo_profiles_arches.profile_id \
1766 LEFT JOIN fireinfo_arches ON fireinfo_profiles_arches.arch_id = fireinfo_arches.id \
1767 WHERE NOT fireinfo_profiles_arches.profile_id IS NULL \
1768 GROUP BY fireinfo_arches.id ORDER BY count DESC", when
)
1770 return ((r
.arch
, r
.count
) for r
in res
)
1774 def get_hypervisor_map(self
, when
=None):
1775 res
= self
.db
.query("WITH profiles AS (SELECT fireinfo_profiles_with_data_at(%s) AS id), \
1776 virtual_profiles AS (SELECT profiles.id AS profile_id, fireinfo_profiles_virtual.hypervisor_id FROM profiles \
1777 LEFT JOIN fireinfo_profiles_virtual ON profiles.id = fireinfo_profiles_virtual.profile_id \
1778 WHERE fireinfo_profiles_virtual.profile_id IS NOT NULL) \
1779 SELECT COALESCE(fireinfo_hypervisors.name, %s) AS name, \
1780 COUNT(*)::float / (SELECT COUNT(*) FROM virtual_profiles) AS count FROM virtual_profiles \
1781 LEFT JOIN fireinfo_hypervisors ON virtual_profiles.hypervisor_id = fireinfo_hypervisors.id \
1782 GROUP BY fireinfo_hypervisors.name ORDER BY count DESC", when
, "unknown")
1784 return ((r
.name
, r
.count
) for r
in res
)
1786 def get_virtual_ratio(self
, when
=None):
1787 res
= self
.db
.get("WITH profiles AS (SELECT fireinfo_profiles_with_data_at(%s) AS id) \
1788 SELECT COUNT(*)::float / (SELECT COUNT(*) FROM profiles) AS count FROM profiles \
1789 LEFT JOIN fireinfo_profiles_virtual ON profiles.id = fireinfo_profiles_virtual.profile_id \
1790 WHERE fireinfo_profiles_virtual.profile_id IS NOT NULL", when
)
1797 def get_releases_map(self
, when
=None):
1798 res
= self
.db
.query("WITH profiles AS (SELECT fireinfo_profiles_with_data_at(%s) AS id) \
1799 SELECT fireinfo_releases.name, COUNT(*)::float / (SELECT COUNT(*) FROM profiles) AS count FROM profiles \
1800 LEFT JOIN fireinfo_profiles_releases ON profiles.id = fireinfo_profiles_releases.profile_id \
1801 LEFT JOIN fireinfo_releases ON fireinfo_profiles_releases.release_id = fireinfo_releases.id \
1802 GROUP BY fireinfo_releases.name ORDER BY count DESC", when
)
1804 return ((r
.name
, r
.count
) for r
in res
)
1806 def get_kernels_map(self
, when
=None):
1807 res
= self
.db
.query("WITH profiles AS (SELECT fireinfo_profiles_with_data_at(%s) AS id) \
1808 SELECT fireinfo_kernels.name, COUNT(*)::float / (SELECT COUNT(*) FROM profiles) AS count FROM profiles \
1809 LEFT JOIN fireinfo_profiles_kernels ON profiles.id = fireinfo_profiles_kernels.profile_id \
1810 LEFT JOIN fireinfo_kernels ON fireinfo_profiles_kernels.kernel_id = fireinfo_kernels.id \
1811 GROUP BY fireinfo_kernels.name ORDER BY count DESC", when
)
1813 return ((r
.name
, r
.count
) for r
in res
)
1815 def _process_devices(self
, devices
):
1819 dev
= Device(self
.backend
, dev
.get("id", None), dev
)
1824 def get_driver_map(self
, driver
, when
=None):
1825 res
= self
.db
.query("WITH profiles AS (SELECT fireinfo_profiles_with_data_at(%s) AS id), \
1826 devices AS (SELECT * FROM profiles \
1827 LEFT JOIN fireinfo_profiles_devices ON profiles.id = fireinfo_profiles_devices.profile_id \
1828 LEFT JOIN fireinfo_devices ON fireinfo_profiles_devices.device_id = fireinfo_devices.id \
1829 WHERE driver = %s) \
1830 SELECT subsystem, model, vendor, driver, deviceclass, \
1831 COUNT(*)::float / (SELECT COUNT(*) FROM devices) AS percentage FROM devices \
1832 GROUP BY subsystem, model, vendor, driver, deviceclass \
1833 ORDER BY percentage DESC", when
, driver
)
1835 return self
._process
_devices
(res
)
1838 "pci" : hwdata
.PCI(),
1839 "usb" : hwdata
.USB(),
1842 def get_vendor_string(self
, subsystem
, vendor_id
):
1844 cls
= self
.subsystem2class
[subsystem
]
1848 return cls
.get_vendor(vendor_id
)
1850 def get_model_string(self
, subsystem
, vendor_id
, model_id
):
1852 cls
= self
.subsystem2class
[subsystem
]
1856 return cls
.get_device(vendor_id
, model_id
)
1858 def get_vendor_list(self
, when
=None):
1859 res
= self
.db
.query("WITH profiles AS (SELECT fireinfo_profiles_with_data_at(%s) AS id) \
1860 SELECT DISTINCT fireinfo_devices.subsystem AS subsystem, fireinfo_devices.vendor AS vendor FROM profiles \
1861 LEFT JOIN fireinfo_profiles_devices ON profiles.id = fireinfo_profiles_devices.profile_id \
1862 LEFT JOIN fireinfo_devices ON fireinfo_profiles_devices.device_id = fireinfo_devices.id \
1863 WHERE NOT fireinfo_devices.driver = ANY(%s)", when
, IGNORED_DEVICES
)
1867 vendor
= self
.get_vendor_string(row
.subsystem
, row
.vendor
)
1869 # Drop if vendor could not be determined
1874 vendors
[vendor
].append((row
.subsystem
, row
.vendor
))
1876 vendors
[vendor
] = [(row
.subsystem
, row
.vendor
)]
1878 vendors
= vendors
.items()
1879 return sorted(vendors
)
1881 def get_devices_by_vendor(self
, subsystem
, vendor
, when
=None):
1882 res
= self
.db
.query("WITH profiles AS (SELECT fireinfo_profiles_with_data_at(%s) AS id), \
1883 devices AS (SELECT * FROM profiles \
1884 LEFT JOIN fireinfo_profiles_devices ON profiles.id = fireinfo_profiles_devices.profile_id \
1885 LEFT JOIN fireinfo_devices ON fireinfo_profiles_devices.device_id = fireinfo_devices.id \
1886 WHERE NOT fireinfo_devices.driver = ANY(%s)), \
1887 vendor_devices AS (SELECT * FROM devices WHERE devices.subsystem = %s AND devices.vendor = %s) \
1888 SELECT subsystem, model, vendor, driver, deviceclass FROM vendor_devices \
1889 GROUP BY subsystem, model, vendor, driver, deviceclass", when
, IGNORED_DEVICES
, subsystem
, vendor
)
1891 return self
._process
_devices
(res
)
1893 def get_device_percentage(self
, subsystem
, vendor
, model
, when
=None):
1894 res
= self
.db
.get("WITH profiles AS (SELECT fireinfo_profiles_with_data_at(%s) AS id), \
1895 devices AS (SELECT * FROM profiles \
1896 LEFT JOIN fireinfo_profiles_devices ON profiles.id = fireinfo_profiles_devices.profile_id \
1897 LEFT JOIN fireinfo_devices ON fireinfo_profiles_devices.device_id = fireinfo_devices.id) \
1898 SELECT COUNT(*)::float / (SELECT COUNT(*) FROM devices) AS percentage FROM devices \
1899 WHERE devices.subsystem = %s AND devices.vendor = %s AND devices.model = %s",
1900 when
, subsystem
, vendor
, model
)
1903 return res
.percentage
1905 def get_device_in_profile(self
, subsystem
, vendor
, model
, limit
=10, when
=None):
1906 res
= self
.db
.query("WITH profiles AS (SELECT fireinfo_profiles_with_data_at(%s) AS id), \
1907 profiles_with_device AS (SELECT DISTINCT fireinfo_profiles.public_id FROM profiles \
1908 LEFT JOIN fireinfo_profiles ON profiles.id = fireinfo_profiles.id \
1909 LEFT JOIN fireinfo_profiles_devices ON profiles.id = fireinfo_profiles_devices.profile_id \
1910 LEFT JOIN fireinfo_devices ON fireinfo_profiles_devices.device_id = fireinfo_devices.id \
1911 WHERE fireinfo_devices.subsystem = %s AND fireinfo_devices.vendor = %s \
1912 AND fireinfo_devices.model = %s) \
1913 SELECT * FROM profiles_with_device ORDER BY RANDOM() LIMIT %s",
1914 when
, subsystem
, vendor
, model
, limit
)
1916 return (r
.public_id
for r
in res
)
1918 def get_network_zones_map(self
, when
=None):
1919 res
= self
.db
.get("WITH profiles AS (SELECT fireinfo_profiles_with_data_at(%s) AS id) \
1920 SELECT COUNT(NULLIF(has_red, FALSE))::float / (SELECT COUNT(*) FROM profiles) AS has_red, \
1921 COUNT(NULLIF(has_green, FALSE))::float / (SELECT COUNT(*) FROM profiles) AS has_green, \
1922 COUNT(NULLIF(has_orange, FALSE))::float / (SELECT COUNT(*) FROM profiles) AS has_orange, \
1923 COUNT(NULLIF(has_blue, FALSE))::float / (SELECT COUNT(*) FROM profiles) AS has_blue FROM profiles \
1924 LEFT JOIN fireinfo_profiles_networks ON profiles.id = fireinfo_profiles_networks.profile_id \
1925 WHERE fireinfo_profiles_networks.profile_id IS NOT NULL", when
)