]> git.ipfire.org Git - ipfire.org.git/blame - src/web/fireinfo.py
Migrate to libloc
[ipfire.org.git] / src / web / fireinfo.py
CommitLineData
66862195
MT
1#!/usr/bin/python
2
66862195 3import datetime
66862195
MT
4import logging
5import re
a95c2f97 6import json
66862195
MT
7import tornado.web
8
a95c2f97 9from .. import fireinfo
66862195 10
b89dd000 11from . import auth
124a8404 12from . import base
96c9bb79 13from . import ui_modules
66862195 14
b89dd000 15class BaseHandler(auth.CacheMixin, base.BaseHandler):
66862195
MT
16 @property
17 def when(self):
18 return self.get_argument_date("when", None)
19
20
21MIN_PROFILE_VERSION = 0
22MAX_PROFILE_VERSION = 0
23
24class Profile(dict):
25 def __getattr__(self, key):
26 try:
27 return self[key]
28 except KeyError:
11347e46 29 raise AttributeError(key)
66862195
MT
30
31 def __setattr__(self, key, val):
32 self[key] = val
33
34
96c9bb79 35class ProfileSendHandler(BaseHandler):
66862195
MT
36 def check_xsrf_cookie(self):
37 # This cookie is not required here.
38 pass
39
40 def prepare(self):
41 # Create an empty profile.
42 self.profile = Profile()
43
44 def __check_attributes(self, profile):
45 """
46 Check for attributes that must be provided,
47 """
48 attributes = (
49 "private_id",
50 "profile_version",
51 "public_id",
52 )
53 for attr in attributes:
11347e46 54 if attr not in profile:
66862195
MT
55 raise tornado.web.HTTPError(400, "Profile lacks '%s' attribute: %s" % (attr, profile))
56
57 def __check_valid_ids(self, profile):
58 """
59 Check if IDs contain valid data.
60 """
61 for id in ("public_id", "private_id"):
62 if re.match(r"^([a-f0-9]{40})$", "%s" % profile[id]) is None:
63 raise tornado.web.HTTPError(400, "ID '%s' has wrong format: %s" % (id, profile))
64
65 def __check_equal_ids(self, profile):
66 """
67 Check if public_id and private_id are equal.
68 """
69 if profile.public_id == profile.private_id:
70 raise tornado.web.HTTPError(400, "Public and private IDs are equal: %s" % profile)
71
72 def __check_matching_ids(self, profile):
73 """
74 Check if a profile with the given public_id is already in the
75 database. If so we need to check if the private_id matches.
76 """
77 p = self.profiles.find_one({ "public_id" : profile["public_id"]})
78 if not p:
79 return
80
81 p = Profile(p)
82 if p.private_id != profile.private_id:
83 raise tornado.web.HTTPError(400, "Mismatch of private_id: %s" % profile)
84
85 def __check_profile_version(self, profile):
86 """
87 Check if this version of the server software does support the
88 received profile.
89 """
90 version = profile.profile_version
91
92 if version < MIN_PROFILE_VERSION or version > MAX_PROFILE_VERSION:
93 raise tornado.web.HTTPError(400,
94 "Profile version is not supported: %s" % version)
95
96 def check_profile_blob(self, profile):
97 """
98 This method checks if the blob is sane.
99 """
100 checks = (
101 self.__check_attributes,
102 self.__check_valid_ids,
103 self.__check_equal_ids,
104 self.__check_profile_version,
105 # These checks require at least one database query and should be done
106 # at last.
107 self.__check_matching_ids,
108 )
109
110 for check in checks:
111 check(profile)
112
113 # If we got here, everything is okay and we can go on...
114
115 def get_profile_blob(self):
116 profile = self.get_argument("profile", None)
117
118 # Send "400 bad request" if no profile was provided
119 if not profile:
120 raise tornado.web.HTTPError(400, "No profile received")
121
122 # Try to decode the profile.
123 try:
a95c2f97 124 return json.loads(profile)
11347e46 125 except json.decoder.JSONDecodeError as e:
66862195
MT
126 raise tornado.web.HTTPError(400, "Profile could not be decoded: %s" % e)
127
128 # The GET method is only allowed in debugging mode.
129 def get(self, public_id):
130 if not self.application.settings["debug"]:
fe947d95 131 raise tornado.web.HTTPError(405)
66862195
MT
132
133 return self.post(public_id)
134
135 def post(self, public_id):
136 profile_blob = self.get_profile_blob()
137 #self.check_profile_blob(profile_blob)
138
66862195 139 # Handle the profile.
a69e87a1
MT
140 with self.db.transaction():
141 try:
440aba92
MT
142 self.fireinfo.handle_profile(public_id, profile_blob,
143 country_code=self.current_country_code)
66862195 144
240e9253
MT
145 except fireinfo.ProfileParserError as e:
146 raise tornado.web.HTTPError(400, "Could not parse profile: %s" % e)
66862195
MT
147
148 self.finish("Your profile was successfully saved to the database.")
149
150
96c9bb79 151class IndexHandler(BaseHandler):
66862195 152 def get(self):
c4099434 153 data = {
11ee2139
MT
154 # Release
155 "latest_release" : self.backend.releases.get_latest(),
156
84604476 157 # Hardware
5a34028b
MT
158 "arches" : self.fireinfo.get_arch_map(when=self.when),
159 "cpu_vendors" : self.fireinfo.get_cpu_vendors_map(when=self.when),
84604476
MT
160 "memory_avg" : self.backend.fireinfo.get_average_memory_amount(when=self.when),
161
11ee2139
MT
162 # Virtualization
163 "hypervisors" : self.fireinfo.get_hypervisor_map(when=self.when),
164 "virtual_ratio" : self.fireinfo.get_virtual_ratio(when=self.when),
574a88c7
MT
165
166 # Location
167 "locations" : self.fireinfo.get_geo_location_map(when=self.when),
c4099434
MT
168 }
169
c4099434 170 self.render("fireinfo/index.html", **data)
66862195 171
66862195 172
1e3b2aad
MT
173class DriverDetail(BaseHandler):
174 def get(self, driver):
175 self.render("fireinfo/driver.html", driver=driver,
176 driver_map=self.fireinfo.get_driver_map(driver, when=self.when))
177
178
b84b407f 179class ProfileHandler(BaseHandler):
66862195
MT
180 def get(self, profile_id):
181 profile = self.fireinfo.get_profile(profile_id, when=self.when)
182
183 if not profile or not profile.is_showable():
b84b407f 184 raise tornado.web.HTTPError(404)
66862195 185
b84b407f 186 self.render("fireinfo/profile.html", profile=profile)
66862195
MT
187
188
96c9bb79 189class RandomProfileHandler(BaseHandler):
66862195
MT
190 def get(self):
191 profile_id = self.fireinfo.get_random_profile(when=self.when)
192 if profile_id is None:
193 raise tornado.web.HTTPError(404)
194
195 self.redirect("/profile/%s" % profile_id)
196
197
ed2e3c1f
MT
198class ReleasesHandler(BaseHandler):
199 def get(self):
200 data = {
201 "releases" : self.fireinfo.get_releases_map(when=self.when),
202 "kernels" : self.fireinfo.get_kernels_map(when=self.when),
203 }
204
ed2e3c1f
MT
205 return self.render("fireinfo/releases.html", **data)
206
207
19518d6e 208class ProcessorsHandler(BaseHandler):
66862195 209 def get(self):
19518d6e 210 flags = {}
66862195 211
19518d6e
MT
212 for platform in ("arm", "x86"):
213 flags[platform] = \
214 self.fireinfo.get_common_cpu_flags_by_platform(platform, when=self.when)
66862195 215
19518d6e 216 return self.render("fireinfo/processors.html", flags=flags)
66862195
MT
217
218
8ab37e0b
MT
219class VendorsHandler(BaseHandler):
220 def get(self):
221 vendors = self.fireinfo.get_vendor_list(when=self.when)
222
223 self.render("fireinfo/vendors.html", vendors=vendors)
224
225
226class VendorHandler(BaseHandler):
66862195 227 def get(self, subsystem, vendor_id):
8ab37e0b
MT
228 devices = self.fireinfo.get_devices_by_vendor(subsystem, vendor_id, when=self.when)
229 if not devices:
230 raise tornado.web.HTTPError(404)
66862195
MT
231
232 vendor_name = self.fireinfo.get_vendor_string(subsystem, vendor_id)
233
851a00bc 234 self.render("fireinfo/vendor.html", vendor_name=vendor_name, devices=devices)
66862195
MT
235
236
96c9bb79 237class DeviceTableModule(ui_modules.UIModule):
3697181e 238 def render(self, devices, show_group=True, embedded=False):
96c9bb79 239 return self.render_string("fireinfo/modules/table-devices.html",
3697181e 240 devices=devices, show_group=show_group, embedded=embedded)
96c9bb79
MT
241
242
243class DeviceAndGroupsTableModule(ui_modules.UIModule):
244 def render(self, devices):
245 _ = self.locale.translate
246
247 groups = {}
248
249 for device in devices:
250 if device.cls not in groups:
251 groups[device.cls] = []
252
253 groups[device.cls].append(device)
254
255 # Sort all devices
256 for key in list(groups.keys()):
257 groups[key].sort()
258
259 # Order the groups by their name
260 groups = list(groups.items())
261 groups.sort()
262
263 return self.render_string("fireinfo/modules/table-devices-and-groups.html",
264 groups=groups)
dc96f754
MT
265
266
267class AdminIndexHandler(BaseHandler):
268 @tornado.web.authenticated
269 def prepare(self):
270 if not self.current_user.is_staff():
271 raise tornado.web.HTTPError(401)
272
273 @tornado.web.authenticated
274 def get(self):
dc838425 275 with_data, total = self.backend.fireinfo.get_active_profiles()
dc96f754 276
dc838425 277 self.render("fireinfo/admin.html", with_data=with_data, total=total)