]>
git.ipfire.org Git - people/shoehn/ipfire.org.git/blob - webapp/handlers_stasy.py
3 from __future__
import division
15 from handlers_base
import *
17 class StasyBaseHandler(BaseHandler
):
20 return backend
.Stasy()
22 def format_size(self
, s
):
23 units
= ("K", "M", "G", "T")
26 while s
>= 1024 and unit
< len(units
):
30 return "%.1f%s" % (s
, units
[unit
])
32 def cut_string(self
, s
, limit
=15):
38 def render(self
, *args
, **kwargs
):
40 "cut_string" : self
.cut_string
,
41 "format_size" : self
.format_size
,
44 return BaseHandler
.render(self
, *args
, **kwargs
)
47 MIN_PROFILE_VERSION
= 0
48 MAX_PROFILE_VERSION
= 0
51 def __getattr__(self
, key
):
55 raise AttributeError, key
57 def __setattr__(self
, key
, val
):
61 class StasyProfileSendHandler(StasyBaseHandler
):
62 def check_xsrf_cookie(self
):
63 # This cookie is not required here.
68 return self
.stasy
.archives
72 return self
.stasy
.profiles
75 # Create an empty profile.
76 self
.profile
= Profile()
78 def __check_attributes(self
, profile
):
80 Check for attributes that must be provided,
89 for attr
in attributes
:
90 if not profile
.has_key(attr
):
91 raise tornado
.web
.HTTPError(400, "Profile lacks '%s' attribute: %s" % (attr
, profile
))
93 def __check_valid_ids(self
, profile
):
95 Check if IDs contain valid data.
98 for id in ("public_id", "private_id"):
99 if re
.match(r
"^([a-f0-9]{40})$", "%s" % profile
[id]) is None:
100 raise tornado
.web
.HTTPError(400, "ID '%s' has wrong format: %s" % (id, profile
))
102 def __check_equal_ids(self
, profile
):
104 Check if public_id and private_id are equal.
107 if profile
.public_id
== profile
.private_id
:
108 raise tornado
.web
.HTTPError(400, "Public and private IDs are equal: %s" % profile
)
110 def __check_matching_ids(self
, profile
):
112 Check if a profile with the given public_id is already in the
113 database. If so we need to check if the private_id matches.
115 p
= self
.profiles
.find_one({ "public_id" : profile
["public_id"]})
120 if p
.private_id
!= profile
.private_id
:
121 raise tornado
.web
.HTTPError(400, "Mismatch of private_id: %s" % profile
)
123 def __check_profile_version(self
, profile
):
125 Check if this version of the server software does support the
128 version
= profile
.profile_version
130 if version
< MIN_PROFILE_VERSION
or version
> MAX_PROFILE_VERSION
:
131 raise tornado
.web
.HTTPError(400,
132 "Profile version is not supported: %s" % version
)
134 def check_profile(self
):
136 This method checks if the blob is sane.
140 self
.__check
_attributes
,
141 self
.__check
_valid
_ids
,
142 self
.__check
_equal
_ids
,
143 self
.__check
_profile
_version
,
144 # These checks require at least one database query and should be done
146 self
.__check
_matching
_ids
,
152 # If we got here, everything is okay and we can go on...
154 # The GET method is only allowed in debugging mode.
155 def get(self
, public_id
):
156 if not self
.application
.settings
["debug"]:
157 return tornado
.web
.HTTPError(405)
159 return self
.post(public_id
)
161 def post(self
, public_id
):
162 profile
= self
.get_argument("profile", None)
164 # Send "400 bad request" if no profile was provided
166 raise tornado
.web
.HTTPError(400, "No profile received.")
168 # Try to decode the profile.
170 self
.profile
.update(simplejson
.loads(profile
))
171 except simplejson
.decoder
.JSONDecodeError
, e
:
172 raise tornado
.web
.HTTPError(400, "Profile could not be decoded: %s" % e
)
174 # Create a shortcut and overwrite public_id from query string
175 profile
= self
.profile
176 profile
.public_id
= public_id
178 # Add timestamp to the profile
179 profile
.updated
= datetime
.datetime
.utcnow()
181 # Check if profile contains proper data.
184 # Get GeoIP information if address is not defined in rfc1918
185 remote_ips
= self
.request
.remote_ip
.split(", ")
186 for remote_ip
in remote_ips
:
188 addr
= ipaddr
.IPAddress(remote_ip
)
190 # Skip invalid IP addresses.
193 # Check if the given IP address is from a
198 profile
.geoip
= self
.geoip
.get_all(remote_ip
)
201 # Move previous profiles to archive and keep only the latest one
202 # in profiles. This will make full table lookups faster.
203 self
.stasy
.move_profiles({ "public_id" : profile
.public_id
})
205 # Write profile to database
206 id = self
.profiles
.save(profile
)
208 self
.write("Your profile was successfully saved to the database.")
211 logging
.debug("Saved profile: %s" % profile
)
214 logging
.debug("Starting automatic cleanup...")
216 # Remove all profiles that were not updated since 4 weeks.
217 not_updated_since
= datetime
.datetime
.utcnow() - \
218 datetime
.timedelta(weeks
=4)
220 self
.stasy
.move_profiles({ "updated" : { "$lt" : not_updated_since
}})
223 class StasyIndexHandler(StasyBaseHandler
):
224 def _profile_not_found(self
, profile_id
):
226 self
.render("stasy-profile-notfound.html", profile_id
=profile_id
)
229 self
.render("stasy-index.html")
232 profile_id
= self
.get_argument("profile_id", None)
234 raise tornado
.web
.HTTPError(400, "No profile ID was given.")
236 if not self
.stasy
.profile_exists(profile_id
):
237 self
._profile
_not
_found
(profile_id
)
240 self
.redirect("/profile/%s" % profile_id
)
243 class StasyProfileDetailHandler(StasyIndexHandler
):
244 def get(self
, profile_id
):
245 profile
= self
.stasy
.get_profile(profile_id
)
247 self
._profile
_not
_found
(profile_id
)
250 self
.render("stasy-profile-detail.html", profile
=profile
)
253 class StasyStatsHandler(StasyBaseHandler
):
255 self
.render("stasy-stats.html")
258 class StasyStatsCPUHandler(StasyBaseHandler
):
260 return self
.render("stasy-stats-cpus.html",
261 cpu_vendors
=self
.stasy
.cpu_vendors_map
,
262 average_speed
=self
.stasy
.cpu_speed_average
,
263 cpu_speeds
=self
.stasy
.cpu_speed_map
,
264 cpu_cores
=self
.stasy
.get_cpu_cores_map(),
265 bogomips
=self
.stasy
.get_cpu_bogomips_accumulated())
268 class StasyStatsCPUFlagsHandler(StasyBaseHandler
):
275 ("virt", ("vmx", "svm")),
278 for name
, flag
in flags
:
279 kwargs
["cpus_" + name
] = self
.stasy
.get_cpu_flag_map(flag
)
281 return self
.render("stasy-stats-cpu-flags.html", **kwargs
)
283 class StasyStatsMemoryHandler(StasyBaseHandler
):
285 return self
.render("stasy-stats-memory.html",
286 average_memory
=self
.stasy
.memory_average
,
287 memory
=self
.stasy
.get_memory_map())
290 class StasyStatsOSesHandler(StasyBaseHandler
):
292 return self
.render("stasy-stats-oses.html",
293 arches
=self
.stasy
.arch_map
,
294 kernels
=self
.stasy
.kernel_map
,
295 releases
=self
.stasy
.release_map
)
298 class StasyStatsVirtualHandler(StasyBaseHandler
):
300 return self
.render("stasy-stats-virtual.html",
301 hypervisor_vendors
= self
.stasy
.hypervisor_map
,
302 is_virtual
= self
.stasy
.virtual_map
)
304 class StasyStatsGeoHandler(StasyBaseHandler
):
306 return self
.render("stasy-stats-geo.html",
307 languages
= self
.stasy
.get_language_map(),
308 geo_locations
= self
.stasy
.get_geo_location_map())
311 class StasyStatsNetworkHandler(StasyBaseHandler
):
313 return self
.render("stasy-stats-network.html",
314 network_zones
=self
.stasy
.get_network_zones_map())
317 class StasyStatsVendorDetail(StasyBaseHandler
):
318 def get(self
, bus
, vendor_id
):
324 cls
= bus2cls
[bus
.lower()]
325 vendor_name
= cls().get_vendor(vendor_id
)
327 # Get a list of all models we know from this vendor
328 models
= self
.stasy
.get_models_by_vendor(bus
, vendor_id
)
330 self
.render("stasy-vendor-detail.html",
331 vendor_name
=vendor_name
, models
=models
)
334 class StasyStatsModelDetail(StasyBaseHandler
):
335 def get(self
, bus
, vendor_id
, model_id
):
341 cls
= bus2cls
[bus
.lower()]
343 vendor_name
= cls().get_vendor(vendor_id
)
344 model_name
= cls().get_device(vendor_id
, model_id
)
347 self
.stasy
.get_device_percentage(bus
, vendor_id
, model_id
) * 100
349 self
.render("stasy-model-detail.html",
351 vendor_name
=vendor_name
,
353 model_name
=model_name
,
354 percentage
=percentage
,
358 class AdminFireinfoStatsHandler(StasyBaseHandler
):
360 _
= self
.locale
.translate
364 data
["profiles_count"], data
["profiles_count_all"] = \
365 self
.stasy
.get_profile_ratio()
367 data
["archives_count"] = self
.stasy
.get_archives_count()
370 #since = { "hours" : 24 }
371 #updates = self.stasy.get_updates_by_release_since(since)
372 #updates[_("All versions")] = self.stasy.get_updated_since(since).count()
373 #data["updated_since_24h"] = updates
375 self
.render("stasy-stats-admin.html", **data
)