]>
Commit | Line | Data |
---|---|---|
372efc19 MT |
1 | #!/usr/bin/python |
2 | ||
91a446f0 MT |
3 | from __future__ import division |
4 | ||
cbb9726a | 5 | import datetime |
372efc19 MT |
6 | import hwdata |
7 | import logging | |
8 | import pymongo | |
abc3bb31 | 9 | import re |
372efc19 MT |
10 | |
11 | from misc import Singleton | |
12 | ||
13 | DATABASE_HOST = ["irma.ipfire.org", "madeye.ipfire.org"] | |
14 | DATABASE_NAME = "stasy" | |
15 | ||
91a446f0 | 16 | CPU_SPEED_CONSTRAINTS = (0, 500, 1000, 1500, 2000, 2500, 3000, 3500) |
c552a83c | 17 | MEMORY_CONSTRAINTS = (0, 128, 256, 512, 1024, 2048, 4096, 8128, 16384) |
372efc19 | 18 | |
abc3bb31 MT |
19 | CPU_STRINGS = ( |
20 | # AMD | |
21 | (r"(AMD Athlon).*(XP).*", r"\1 \2"), | |
22 | (r"(AMD Phenom).* ([0-9]+) .*", r"\1 \2"), | |
23 | (r"(AMD Phenom).*", r"\1"), | |
24 | (r"(AMD Sempron).*", r"\1"), | |
25 | (r"AMD Athlon.* II X2 ([a-z0-9]+).*", r"AMD Athlon X2 \1"), | |
26 | (r"(Geode).*", r"\1"), | |
27 | ||
28 | # Intel | |
29 | (r"Intel.*(Atom|Celeron).*CPU\s*([A-Z0-9]+) .*", r"Intel \1 \2"), | |
30 | (r"(Intel).*(Celeron).*", r"\1 \2"), | |
31 | (r"Intel.* Core.*2 Duo CPU .* ([A-Z0-9]+) .*", r"Intel C2D \1"), | |
32 | (r"Intel.* Core.*2 CPU .* ([A-Z0-9]+) .*", r"Intel C2 \1"), | |
33 | (r"Intel.* Core.*2 Quad CPU .* ([A-Z0-9]+) .*", r"Intel C2Q \1"), | |
34 | (r"Intel.* Xeon.* CPU .* ([A-Z0-9]+) .*", r"Intel Xeon \1"), | |
35 | (r"(Intel).*(Xeon).*", r"\1 \2"), | |
36 | (r"Intel.* Pentium.* (D|4) .*", r"Intel Pentium \1"), | |
37 | (r"Intel.* Pentium.* Dual .* ([A-Z0-9]+) .*", r"Intel Pentium Dual \1"), | |
38 | (r"Pentium.* Dual-Core .* ([A-Z0-9]+) .*", r"Intel Pentium Dual \1"), | |
39 | (r"(Pentium I{2,3}).*", r"Intel \1"), | |
40 | (r"(Celeron \(Coppermine\))", r"Intel Celeron"), | |
41 | ||
42 | # VIA | |
43 | (r"(VIA \w*).*", r"\1"), | |
44 | ) | |
45 | ||
372efc19 MT |
46 | class ProfileDict(object): |
47 | def __init__(self, data): | |
48 | self._data = data | |
49 | ||
50 | ||
51 | class ProfileCPU(ProfileDict): | |
52 | @property | |
53 | def arch(self): | |
54 | return self._data.get("arch") | |
55 | ||
56 | @property | |
57 | def vendor(self): | |
58 | return self._data.get("vendor") | |
59 | ||
91a446f0 MT |
60 | @property |
61 | def speed(self): | |
62 | return self._data.get("speed") | |
63 | ||
abc3bb31 MT |
64 | @property |
65 | def friendly_speed(self): | |
66 | if self.speed < 1000: | |
67 | return "%dMHz" % self.speed | |
68 | ||
69 | return "%.1fGHz" % round(self.speed / 1000, 1) | |
70 | ||
91a446f0 MT |
71 | @property |
72 | def bogomips(self): | |
73 | return self._data.get("bogomips") | |
74 | ||
372efc19 MT |
75 | @property |
76 | def model(self): | |
77 | return self._data.get("model") | |
78 | ||
79 | @property | |
80 | def model_string(self): | |
81 | return self._data.get("model_string") | |
82 | ||
83 | @property | |
84 | def flags(self): | |
85 | return self._data.get("flags") | |
86 | ||
91a446f0 MT |
87 | @property |
88 | def count(self): | |
89 | return self._data.get("count") | |
90 | ||
372efc19 MT |
91 | @property |
92 | def capable_64bit(self): | |
93 | return "lm" in self.flags | |
94 | ||
95 | @property | |
96 | def capable_pae(self): | |
97 | return "pae" in self.flags | |
98 | ||
99 | @property | |
100 | def capable_virt(self): | |
101 | return "vmx" in self.flags or "svm" in self.flags | |
102 | ||
abc3bb31 MT |
103 | @property |
104 | def friendly_vendor(self): | |
105 | s = self.model_string | |
106 | for pattern, repl in CPU_STRINGS: | |
107 | if re.match(pattern, s) is None: | |
108 | continue | |
109 | return re.sub(pattern, repl, s) | |
110 | ||
111 | return s | |
112 | ||
113 | @property | |
114 | def friendly_string(self): | |
115 | return "%s @ %s" % (self.friendly_vendor, self.friendly_speed) | |
116 | ||
372efc19 MT |
117 | |
118 | class ProfileHypervisor(ProfileDict): | |
119 | def __repr__(self): | |
120 | return "<%s %s-%s>" % (self.__class__.__name__, self.vendor, self.type) | |
121 | ||
122 | @property | |
123 | def vendor(self): | |
124 | return self._data.get("vendor") | |
125 | ||
372efc19 MT |
126 | @property |
127 | def type(self): | |
128 | return self._data.get("type") | |
129 | ||
130 | ||
07785a9c MT |
131 | class ProfileNetwork(ProfileDict): |
132 | def has_zone(self, name): | |
133 | return self._data.get(name) | |
134 | ||
135 | @property | |
136 | def green(self): | |
137 | return self._data.get("green") | |
138 | ||
139 | @property | |
140 | def red(self): | |
141 | return self._data.get("red") | |
142 | ||
143 | @property | |
144 | def blue(self): | |
145 | return self._data.get("blue") | |
146 | ||
147 | @property | |
148 | def orange(self): | |
149 | return self._data.get("orange") | |
150 | ||
151 | ||
372efc19 MT |
152 | class ProfileDevice(ProfileDict): |
153 | subsystem2class = { | |
154 | "pci" : hwdata.PCI, | |
155 | "usb" : hwdata.USB, | |
156 | } | |
157 | ||
91a446f0 MT |
158 | classid2name = { |
159 | "pci" : { | |
bc19cabd | 160 | "00" : "Unclassified", |
91a446f0 MT |
161 | "01" : "Mass storage", |
162 | "02" : "Network", | |
163 | "03" : "Display", | |
164 | "04" : "Multimedia", | |
165 | "05" : "Memory controller", | |
166 | "06" : "Bridge", | |
167 | "07" : "Communication", | |
168 | "08" : "Generic system peripheral", | |
169 | "09" : "Input device", | |
170 | "0a" : "Docking station", | |
171 | "0b" : "Processor", | |
172 | "0c" : "Serial bus", | |
173 | "0d" : "Wireless", | |
174 | "0e" : "Intelligent controller", | |
175 | "0f" : "Satellite communications controller", | |
bc19cabd | 176 | "10" : "Encryption", |
91a446f0 MT |
177 | "11" : "Signal processing controller", |
178 | "ff" : "Unassigned class", | |
179 | }, | |
180 | ||
181 | "usb" : { | |
bc19cabd | 182 | "00" : "Unclassified", |
91a446f0 MT |
183 | "01" : "Multimedia", |
184 | "02" : "Communication", | |
185 | "03" : "Input device", | |
bc19cabd MT |
186 | "05" : "Generic system peripheral", |
187 | "06" : "Image", | |
91a446f0 MT |
188 | "07" : "Printer", |
189 | "08" : "Mass storage", | |
190 | "09" : "Hub", | |
bc19cabd MT |
191 | "0a" : "Communication", |
192 | "0b" : "Smart card", | |
193 | "0d" : "Encryption", | |
91a446f0 | 194 | "0e" : "Display", |
bc19cabd | 195 | "0f" : "Personal Healthcare", |
91a446f0 MT |
196 | "dc" : "Diagnostic Device", |
197 | "e0" : "Wireless", | |
bc19cabd MT |
198 | "ef" : "Unclassified", |
199 | "fe" : "Unclassified", | |
200 | "ff" : "Unclassified", | |
91a446f0 MT |
201 | } |
202 | } | |
203 | ||
204 | def __cmp__(self, other): | |
205 | return cmp(self.vendor, other.vendor) or \ | |
206 | cmp(self.model, other.model) or \ | |
207 | cmp(self.driver, other.driver) | |
208 | ||
372efc19 MT |
209 | @property |
210 | def model(self): | |
211 | return self._data.get("model") | |
212 | ||
213 | @property | |
214 | def model_string(self): | |
215 | cls = self.subsystem2class[self.subsystem] | |
216 | ||
217 | return cls().get_device(self.vendor, self.model) | |
218 | ||
219 | @property | |
220 | def subsystem(self): | |
221 | return self._data.get("subsystem") | |
222 | ||
223 | @property | |
224 | def vendor(self): | |
225 | return self._data.get("vendor") | |
226 | ||
227 | @property | |
228 | def vendor_string(self): | |
229 | cls = self.subsystem2class[self.subsystem] | |
230 | ||
231 | return cls().get_vendor(self.vendor) | |
232 | ||
233 | @property | |
234 | def driver(self): | |
235 | return self._data.get("driver") | |
236 | ||
91a446f0 MT |
237 | @property |
238 | def cls(self): | |
239 | classid = self._data.get("deviceclass") | |
240 | ||
241 | if self.subsystem == "pci": | |
242 | classid = classid[:-4] | |
243 | if len(classid) == 1: | |
244 | classid = "0%s" % classid | |
245 | ||
246 | elif self.subsystem == "usb" and classid: | |
247 | classid = classid.split("/")[0] | |
248 | classid = "%02x" % int(classid) | |
249 | ||
250 | try: | |
251 | return self.classid2name[self.subsystem][classid] | |
252 | except KeyError: | |
253 | return "N/A" | |
254 | ||
372efc19 MT |
255 | |
256 | class Profile(ProfileDict): | |
91a446f0 MT |
257 | def __init__(self, profile_blob): |
258 | ProfileDict.__init__(self, profile_blob.get("profile")) | |
372efc19 | 259 | |
91a446f0 MT |
260 | self.public_id = profile_blob.get("public_id") |
261 | self.updated = profile_blob.get("updated") | |
262 | self._geoip = profile_blob.get("geoip", None) | |
372efc19 MT |
263 | |
264 | def __repr__(self): | |
265 | return "<%s %s>" % (self.__class__.__name__, self.public_id) | |
266 | ||
267 | @property | |
268 | def cpu(self): | |
269 | return ProfileCPU(self._data.get("cpu")) | |
270 | ||
271 | @property | |
272 | def devices(self): | |
273 | devices = [] | |
274 | for d in self._data.get("devices"): | |
275 | d = ProfileDevice(d) | |
276 | ||
91a446f0 | 277 | if d.driver in ("pcieport", "usb", "hub"): |
372efc19 MT |
278 | continue |
279 | ||
280 | devices.append(d) | |
281 | ||
282 | return devices | |
283 | ||
284 | @property | |
285 | def hypervisor(self): | |
286 | if self.virtual: | |
287 | return ProfileHypervisor(self._data.get("hypervisor")) | |
288 | ||
289 | @property | |
290 | def virtual(self): | |
291 | return self.system.get("virtual") | |
292 | ||
293 | @property | |
294 | def system(self): | |
295 | return self._data.get("system") | |
296 | ||
297 | @property | |
298 | def release(self): | |
299 | return self.system.get("release") | |
300 | ||
301 | @property | |
302 | def kernel(self): | |
303 | return self.system.get("kernel_release") | |
304 | ||
305 | @property | |
306 | def memory(self): | |
307 | return self.system.get("memory") | |
308 | ||
abc3bb31 MT |
309 | @property |
310 | def friendly_memory(self): | |
311 | units = ("k", "M", "G", "T") | |
312 | ||
313 | mem = self.memory | |
314 | i = 0 | |
315 | while mem >= 1024: | |
316 | mem /= 1024 | |
317 | i += 1 | |
318 | ||
319 | return "%d%s" % (round(mem, 0), units[i]) | |
320 | ||
372efc19 MT |
321 | @property |
322 | def root_size(self): | |
91a446f0 MT |
323 | return self.system.get("root_size") or 0 |
324 | ||
abc3bb31 MT |
325 | @property |
326 | def friendly_root_size(self): | |
327 | units = ("k", "M", "G", "T") | |
328 | ||
329 | size = self.root_size | |
330 | if not size: | |
331 | return | |
332 | ||
333 | i = 0 | |
334 | while size >= 1024: | |
335 | size /= 1024 | |
336 | i += 1 | |
337 | ||
338 | return "%d%s" % (round(size, 0), units[i]) | |
339 | ||
91a446f0 MT |
340 | @property |
341 | def vendor(self): | |
342 | return self.system.get("vendor") | |
343 | ||
344 | @property | |
345 | def model(self): | |
346 | return self.system.get("model") | |
347 | ||
348 | @property | |
349 | def country_code(self): | |
350 | if self._geoip: | |
351 | return self._geoip["country_code"].lower() | |
372efc19 | 352 | |
91a446f0 | 353 | return "unknown" |
372efc19 | 354 | |
07785a9c MT |
355 | @property |
356 | def network(self): | |
357 | network = self._data.get("network", None) | |
358 | if network: | |
359 | return ProfileNetwork(network) | |
360 | ||
372efc19 MT |
361 | |
362 | class Stasy(object): | |
363 | __metaclass__ = Singleton | |
364 | ||
365 | def __init__(self): | |
366 | # Initialize database connection | |
367 | self._conn = pymongo.Connection(DATABASE_HOST) | |
368 | self._db = self._conn[DATABASE_NAME] | |
369 | ||
370 | def get_profile_count(self): | |
371 | # XXX need to implement something to get profiles updated since | |
372 | # a given date | |
373 | ||
374 | # All distinct profiles (based on public_id) | |
cbb9726a MT |
375 | # XXX possibly bad performance |
376 | return len(self._db.profiles.distinct("public_id")) | |
377 | ||
378 | def get_archives_count(self): | |
379 | return self._db.archives.count() | |
372efc19 MT |
380 | |
381 | #def _get_profile_cursor(self, public_id): | |
382 | # c = self._db.profiles.find({ "public_id" : public_id }) | |
383 | # c.sort("updated", pymongo.ASCENDING) | |
384 | # | |
385 | # return c | |
386 | ||
91a446f0 | 387 | def profile_exists(self, public_id): |
910be037 | 388 | return self.query({ "public_id" : public_id }).count() >= 1 |
91a446f0 | 389 | |
372efc19 | 390 | def get_profile(self, public_id): |
54af860e | 391 | p = None |
372efc19 | 392 | # XXX should only find one object in the end |
910be037 | 393 | for p in self.query({ "public_id" : public_id }): |
91a446f0 | 394 | p = Profile(p) |
372efc19 MT |
395 | |
396 | return p | |
397 | ||
398 | def get_profiles(self): | |
399 | # XXX needs nicer database query | |
400 | profiles = [] | |
401 | for p in self._db.profiles.find(): | |
402 | if not p.get("public_id") in profiles: | |
403 | profiles.append(p.get("public_id")) | |
404 | ||
405 | return profiles | |
406 | ||
910be037 MT |
407 | def query(self, query, archives=False, no_virt=False, all=False): |
408 | db = self._db.profiles | |
409 | ||
410 | if archives: | |
411 | db = self.db.archives | |
412 | ||
413 | if not all: | |
414 | # XXX cannot use the index? | |
415 | query.update({ "profile" : { "$exists" : True }}) | |
416 | ||
417 | if no_virt: | |
418 | query.update({ "profile.system.virtual" : False }) | |
419 | ||
420 | logging.debug("Executing query: %s" % query) | |
421 | ||
422 | return db.find(query) | |
423 | ||
372efc19 MT |
424 | @property |
425 | def secret_ids(self): | |
426 | return self._db.profiles.distinct("secret_id") | |
427 | ||
428 | @property | |
429 | def cpus(self): | |
910be037 | 430 | return self.query({}, no_virt=True).distinct("profile.cpu") |
372efc19 MT |
431 | |
432 | @property | |
433 | def cpu_vendors(self): | |
910be037 | 434 | return self.query({}, no_virt=True).distinct("profile.cpu.vendor") |
372efc19 MT |
435 | |
436 | @property | |
91a446f0 | 437 | def cpu_vendors_map(self): |
372efc19 MT |
438 | cpus = {} |
439 | ||
440 | for vendor in self.cpu_vendors: | |
441 | cpus[vendor] = \ | |
910be037 | 442 | self.query({ |
372efc19 | 443 | "profile.cpu.vendor" : vendor |
910be037 | 444 | }, no_virt=True).count() |
372efc19 MT |
445 | |
446 | return cpus | |
447 | ||
448 | @property | |
91a446f0 MT |
449 | def cpu_speed_average(self): |
450 | speed = 0 | |
451 | ||
910be037 | 452 | all = self.query({}, no_virt=True) |
91a446f0 MT |
453 | |
454 | # XXX ugly. needs to be done by group() | |
455 | for m in all: | |
456 | if not m.has_key("profile"): | |
457 | continue | |
458 | speed += m.get("profile").get("cpu").get("speed") | |
459 | ||
460 | return (speed / all.count()) | |
461 | ||
462 | @property | |
463 | def cpu_speed_map(self): | |
464 | cpu_speeds = {} | |
465 | ||
466 | for i in range(len(CPU_SPEED_CONSTRAINTS) - 1): | |
467 | min, max = CPU_SPEED_CONSTRAINTS[i:i+2] | |
468 | ||
469 | cpu_speeds[min, max] = \ | |
910be037 MT |
470 | self.query({ |
471 | "profile.cpu.speed" : { | |
91a446f0 MT |
472 | "$gte" : min, "$lt" : max |
473 | } | |
910be037 | 474 | }, no_virt=True).count() |
91a446f0 MT |
475 | |
476 | return cpu_speeds | |
477 | ||
478 | def get_memory_map(self): | |
372efc19 MT |
479 | memory = {} |
480 | ||
481 | for i in range(len(MEMORY_CONSTRAINTS) - 1): | |
482 | min, max = MEMORY_CONSTRAINTS[i:i+2] | |
483 | ||
484 | memory[min, max] = \ | |
910be037 | 485 | self.query( |
372efc19 MT |
486 | { "profile.system.memory" : { |
487 | "$gte" : min * 1024, "$lt" : max * 1024 | |
488 | } | |
910be037 | 489 | }, no_virt=True).count() |
372efc19 MT |
490 | |
491 | return memory | |
492 | ||
493 | @property | |
494 | def memory_average(self): | |
495 | memory = 0 | |
496 | ||
910be037 | 497 | all = self.query({}, no_virt=True) |
372efc19 MT |
498 | |
499 | # XXX ugly. needs to be done by group() | |
500 | for m in all: | |
501 | if not m.has_key("profile"): | |
502 | continue | |
503 | memory += int(m.get("profile").get("system").get("memory")) | |
504 | ||
505 | return (memory / all.count()) / 1024 | |
506 | ||
507 | @property | |
508 | def hypervisor_vendors(self): | |
910be037 | 509 | return self.query({}).distinct("profile.hypervisor.vendor") |
372efc19 MT |
510 | |
511 | @property | |
512 | def hypervisor_map(self): | |
513 | hypervisors = {} | |
514 | ||
515 | for hypervisor in self.hypervisor_vendors: | |
516 | hypervisors[hypervisor] = \ | |
910be037 | 517 | self.query({ |
372efc19 MT |
518 | "profile.hypervisor.vendor" : hypervisor |
519 | }).count() | |
520 | ||
521 | return hypervisors | |
522 | ||
523 | @property | |
524 | def hypervisor_models(self): | |
910be037 | 525 | return self.query({}).distinct("profile.hypervisor.model") |
372efc19 MT |
526 | |
527 | @property | |
528 | def virtual_map(self): | |
529 | virtual = { | |
530 | True: None, | |
531 | False: None, | |
532 | } | |
533 | ||
534 | for k in virtual.keys(): | |
535 | virtual[k] = \ | |
910be037 | 536 | self.query({ "profile.system.virtual": k }).count() |
372efc19 MT |
537 | |
538 | return virtual | |
539 | ||
540 | @property | |
541 | def languages(self): | |
910be037 | 542 | return self.query({}).distinct("profile.system.language") |
372efc19 | 543 | |
91a446f0 MT |
544 | def get_language_map(self): |
545 | languages = {} | |
546 | ||
547 | for language in self.languages: | |
548 | languages[language] = \ | |
910be037 | 549 | self.query({ |
91a446f0 MT |
550 | "profile.system.language" : language |
551 | }).count() | |
552 | ||
553 | return languages | |
554 | ||
372efc19 MT |
555 | @property |
556 | def vendors(self): | |
910be037 | 557 | return self.query({}).distinct("profile.system.vendor") |
372efc19 MT |
558 | |
559 | @property | |
560 | def vendor_map(self): | |
561 | vendors = {} | |
562 | ||
563 | for vendor in self.vendors: | |
564 | vendors[vendor] = \ | |
910be037 | 565 | self.query({ |
372efc19 MT |
566 | "profile.system.vendor" : vendor |
567 | }).count() | |
568 | ||
569 | return vendors | |
570 | ||
571 | @property | |
572 | def models(self): | |
910be037 | 573 | return self.query({}).distinct("profile.system.model") |
372efc19 | 574 | |
91a446f0 MT |
575 | @property |
576 | def model_map(self): | |
577 | models = {} | |
578 | ||
579 | for model in self.models: | |
580 | models[model] = \ | |
910be037 | 581 | self.query({ |
91a446f0 MT |
582 | "profile.system.model" : model |
583 | }).count() | |
584 | ||
585 | return models | |
586 | ||
587 | @property | |
588 | def arches(self): | |
910be037 | 589 | return self.query({}).distinct("profile.cpu.arch") |
91a446f0 MT |
590 | |
591 | @property | |
592 | def arch_map(self): | |
593 | arches = {} | |
594 | ||
595 | for arch in self.arches: | |
596 | arches[arch] = \ | |
910be037 | 597 | self.query({ |
91a446f0 MT |
598 | "profile.cpu.arch" : arch |
599 | }).count() | |
600 | ||
601 | return arches | |
602 | ||
603 | @property | |
604 | def kernels(self): | |
910be037 | 605 | return self.query({}).distinct("profile.system.kernel_release") |
91a446f0 MT |
606 | |
607 | @property | |
608 | def kernel_map(self): | |
609 | kernels = {} | |
610 | ||
611 | for kernel in self.kernels: | |
612 | kernels[kernel] = \ | |
910be037 | 613 | self.query({ |
91a446f0 MT |
614 | "profile.system.kernel_release" : kernel |
615 | }).count() | |
616 | ||
617 | return kernels | |
618 | ||
619 | @property | |
620 | def releases(self): | |
910be037 | 621 | return self.query({}).distinct("profile.system.release") |
91a446f0 MT |
622 | |
623 | @property | |
624 | def release_map(self): | |
625 | releases = {} | |
626 | ||
627 | for release in self.releases: | |
628 | releases[release] = \ | |
910be037 | 629 | self.query({ |
91a446f0 MT |
630 | "profile.system.release" : release |
631 | }).count() | |
632 | ||
633 | return releases | |
634 | ||
635 | def get_device_percentage(self, bus, vendor_id, model_id): | |
910be037 | 636 | profiles_with_device = self.query({ |
91a446f0 MT |
637 | "profile.devices.subsystem" : bus, |
638 | "profile.devices.vendor" : vendor_id, | |
639 | "profile.devices.model" : model_id, | |
640 | }) | |
641 | ||
910be037 | 642 | profiles_all = self.query({}) |
91a446f0 MT |
643 | |
644 | if not profiles_all.count(): | |
645 | return 0 | |
646 | ||
647 | return profiles_with_device.count() / profiles_all.count() | |
648 | ||
910be037 MT |
649 | def get_cpu_flag_map(self, flags): |
650 | # XXX needs a cleanup | |
91a446f0 | 651 | |
910be037 | 652 | _flags = { True : 0 } |
91a446f0 | 653 | |
910be037 MT |
654 | if type(flags) == type("a"): |
655 | flags = [flags] | |
656 | ||
657 | for flag in flags: | |
658 | _flags[True] += \ | |
659 | self.query({ | |
660 | "profile.cpu.flags" : flag, | |
661 | }, no_virt=True).count() | |
91a446f0 | 662 | |
910be037 | 663 | _flags[False] = self.query({}, no_virt=True).count() - _flags[True] |
91a446f0 | 664 | |
910be037 | 665 | return _flags |
91a446f0 MT |
666 | |
667 | @property | |
668 | def geo_locations(self): | |
910be037 | 669 | return [code.lower() for code in self.query({}).distinct("geoip.country_code")] |
91a446f0 MT |
670 | |
671 | def get_geo_location_map(self): | |
672 | geo_locations = {} | |
673 | ||
674 | count = 0 | |
675 | for geo_location in self.geo_locations: | |
676 | geo_locations[geo_location] = \ | |
910be037 | 677 | self.query({ |
bc1a5c5e | 678 | "geoip.country_code" : geo_location.upper() |
91a446f0 MT |
679 | }).count() |
680 | ||
681 | count += geo_locations[geo_location] | |
682 | ||
683 | # XXX must only be systems that have profile data | |
910be037 | 684 | profiles_all = self.query({}) |
91a446f0 MT |
685 | |
686 | unknown_count = profiles_all.count() - count | |
687 | if unknown_count: | |
688 | geo_locations["unknown"] = unknown_count | |
689 | ||
690 | return geo_locations | |
691 | ||
692 | def get_models_by_vendor(self, subsystem, vendor_id): | |
693 | devices = [] | |
694 | ||
695 | # XXX must only be systems that have profile data | |
910be037 | 696 | profiles_all = self.query({}) |
91a446f0 MT |
697 | |
698 | for profile in profiles_all: | |
699 | if not profile.has_key("profile"): | |
700 | continue | |
701 | ||
702 | profile = Profile(profile) | |
703 | ||
704 | for device in profile.devices: | |
705 | if not device.vendor == vendor_id: | |
706 | continue | |
707 | ||
708 | if not device in devices: | |
709 | devices.append(device) | |
710 | ||
711 | return devices | |
372efc19 | 712 | |
07785a9c MT |
713 | def get_network_zones_map(self): |
714 | zones = { "green" : 0, "blue" : 0, "orange" : 0, "red" : 0 } | |
715 | ||
e6cff1b1 MT |
716 | all = self.query({ "profile.network" : { "$exists" : True }}) |
717 | ||
07785a9c MT |
718 | for zone in zones.keys(): |
719 | zones[zone] = self.query({ | |
720 | "profile.network.%s" % zone : True, | |
e6cff1b1 | 721 | }).count() / all.count() |
07785a9c MT |
722 | |
723 | return zones | |
724 | ||
cbb9726a MT |
725 | def get_profile_ratio(self): |
726 | return (self.query({}).count(), self.get_profile_count()) | |
727 | ||
728 | def get_updated_since(self, since, _query={}): | |
729 | since = datetime.datetime.utcnow() - datetime.timedelta(**since) | |
730 | ||
731 | query = { "updated" : { "$gte" : since }} | |
732 | query.update(_query) | |
733 | ||
734 | return self.query(query) | |
735 | ||
736 | def get_updates_by_release_since(self, since): | |
737 | updates = {} | |
738 | ||
739 | for release in self.releases: | |
740 | updates[release] = self.get_updated_since(since, | |
741 | { "profile.system.release" : release }).count() | |
742 | ||
743 | return updates | |
744 | ||
372efc19 MT |
745 | |
746 | if __name__ == "__main__": | |
747 | s = Stasy() | |
748 |