author | Tero Marttila <terom@paivola.fi> |
Wed, 10 Oct 2012 21:59:34 +0300 | |
changeset 1 | 731d2df704f0 |
parent 0 | 91c739202f06 |
child 3 | 5990b188c54b |
permissions | -rw-r--r-- |
0 | 1 |
from pvl.verkko import db, web |
2 |
||
3 |
from pvl.html import tags as html |
|
4 |
||
5 |
import socket # dns |
|
6 |
||
7 |
import logging; log = logging.getLogger('pvl.verkko.hosts') |
|
8 |
||
1
731d2df704f0
fixup index + non-chunked response (?) + hosts + evil hardcoded db url
Tero Marttila <terom@paivola.fi>
parents:
0
diff
changeset
|
9 |
# XXX: this should actually be DHCPHost |
0 | 10 |
class Host (object) : |
11 |
DATE_FMT = '%Y%m%d' |
|
12 |
||
13 |
def __init__ (self, ip, mac, name=None) : |
|
14 |
self.ip = ip |
|
15 |
self.mac = mac |
|
16 |
self.name = name |
|
17 |
||
18 |
def render_mac (self) : |
|
19 |
if not self.mac : |
|
20 |
return None |
|
21 |
||
22 |
elif len(self.mac) > (6 * 2 + 5) : |
|
23 |
return u'???' |
|
24 |
||
25 |
else : |
|
26 |
return unicode(self.mac) |
|
27 |
||
28 |
def render_name (self) : |
|
29 |
if self.name : |
|
30 |
return self.name.decode('ascii', 'replace') |
|
31 |
else : |
|
32 |
return None |
|
33 |
||
34 |
def when (self) : |
|
35 |
return '{frm} - {to}'.format( |
|
36 |
frm = self.first_seen.strftime(self.DATE_FMT), |
|
37 |
to = self.last_seen.strftime(self.DATE_FMT), |
|
38 |
) |
|
39 |
||
40 |
def dns (self) : |
|
41 |
""" |
|
42 |
Reverse-DNS lookup. |
|
43 |
""" |
|
44 |
||
45 |
if not self.ip : |
|
46 |
return None |
|
47 |
||
48 |
sockaddrs = set(sockaddr for family, socktype, proto, canonname, sockaddr in socket.getaddrinfo(self.ip, 0, 0, 0, 0, socket.AI_NUMERICHOST)) |
|
49 |
||
50 |
for sockaddr in sockaddrs : |
|
51 |
try : |
|
52 |
host, port = socket.getnameinfo(sockaddr, socket.NI_NAMEREQD) |
|
53 |
except socket.gaierror : |
|
54 |
continue |
|
55 |
||
56 |
return host |
|
57 |
||
58 |
def __unicode__ (self) : |
|
59 |
return u"{host.ip} ({host.mac})".format(host=self) |
|
60 |
||
61 |
db.mapper(Host, db.dhcp_hosts, properties=dict( |
|
62 |
id = db.dhcp_hosts.c.rowid, |
|
63 |
#_mac = db.dhcp_hosts.c.mac, |
|
64 |
#_name = db.dhcp_hosts.c.name, |
|
65 |
)) |
|
66 |
||
67 |
HOST_SORT = { |
|
68 |
'id': Host.id, |
|
69 |
'ip': Host.ip, |
|
70 |
'mac': Host.mac, |
|
71 |
'name': Host.name, |
|
72 |
'seen': Host.last_seen, |
|
73 |
None: Host.last_seen.desc(), |
|
74 |
} |
|
75 |
||
76 |
def render_hosts (hosts, title=None) : |
|
77 |
COLS = ( |
|
78 |
#title sort |
|
79 |
('#', None), |
|
80 |
('IP', 'ip'), |
|
81 |
('MAC', 'mac'), |
|
82 |
('Hostname', 'name'), |
|
83 |
('Seen', 'seen'), |
|
84 |
) |
|
85 |
||
86 |
return html.table( |
|
87 |
html.caption(title) if title else None, |
|
88 |
html.thead( |
|
89 |
html.tr( |
|
90 |
html.th( |
|
91 |
html.a(href='?sort={name}'.format(name=sort))(title) if sort else (title) |
|
92 |
) for title, sort in COLS |
|
93 |
) |
|
94 |
), |
|
95 |
html.tbody( |
|
96 |
html.tr(class_=('alternate' if i % 2 else None), id=host.id)( |
|
97 |
html.td(class_='id')( |
|
98 |
html.a(href='/hosts/{host.id}'.format(host=host))( |
|
99 |
'#' #host['rowid']) |
|
100 |
) |
|
101 |
), |
|
102 |
html.td(class_='ip')( |
|
103 |
html.a(href='/hosts/ip/{host.ip}'.format(host=host))(host.ip) |
|
104 |
), |
|
105 |
html.td(class_='mac')( |
|
106 |
html.a(href='/hosts/mac/{host.mac}'.format(host=host))( |
|
107 |
host.render_mac() |
|
108 |
) |
|
109 |
), |
|
110 |
html.td(host.render_name()), |
|
111 |
html.td(host.when()), |
|
112 |
) for i, host in enumerate(hosts) |
|
113 |
) |
|
114 |
) |
|
115 |
||
116 |
def render_host (host, hosts) : |
|
117 |
title = 'DHCP Host: {host}'.format(host=host) |
|
118 |
||
119 |
attrs = ( |
|
120 |
('IP', host.ip), |
|
121 |
('MAC', host.mac), |
|
122 |
('Hostname', host.name), |
|
123 |
('DNS', host.dns()), |
|
124 |
) |
|
125 |
||
126 |
return ( |
|
127 |
html.h2('Host'), |
|
128 |
html.dl( |
|
129 |
(html.dt(title), html.dd(value)) for title, value in attrs |
|
130 |
), |
|
131 |
||
132 |
html.h2('Related'), |
|
133 |
render_hosts(hosts), |
|
134 |
||
1
731d2df704f0
fixup index + non-chunked response (?) + hosts + evil hardcoded db url
Tero Marttila <terom@paivola.fi>
parents:
0
diff
changeset
|
135 |
html.a(href='/hosts')(html('«'), 'Back'), |
0 | 136 |
) |
137 |
||
138 |
def respond (request, db, path) : |
|
139 |
""" |
|
140 |
Handle request |
|
141 |
""" |
|
142 |
||
143 |
hosts = db.query(Host) |
|
144 |
||
145 |
# sort ? |
|
146 |
sort = request.args.get('sort') |
|
147 |
sort = HOST_SORT[sort] |
|
148 |
log.debug("sort: %s", sort) |
|
149 |
||
150 |
hosts = hosts.order_by(sort) |
|
151 |
||
152 |
# index |
|
153 |
if not path : |
|
154 |
title = "DHCP Hosts" |
|
155 |
html = render_hosts(hosts) |
|
156 |
||
157 |
# id |
|
158 |
elif len(path) == 1 : |
|
159 |
id, = path |
|
160 |
id = int(id) |
|
161 |
||
162 |
host = hosts.get(id) |
|
163 |
hosts = hosts.filter((Host.ip == host.ip) | (Host.mac == host.mac)) |
|
164 |
||
165 |
# render |
|
166 |
title = "DHCP Host: {host}".format(host=unicode(host)) |
|
167 |
html = render_host(host, hosts) |
|
168 |
||
169 |
# query |
|
170 |
elif len(path) == 2 : |
|
171 |
attr, value = path |
|
172 |
||
173 |
# fake host |
|
174 |
host = { 'ip': None, 'mac': None, 'name': None } |
|
175 |
host[attr] = value |
|
176 |
||
177 |
host = Host(**host) |
|
178 |
||
179 |
# query |
|
180 |
attr = HOST_SORT[attr] |
|
181 |
log.debug("%s == %s", attr, value) |
|
182 |
||
183 |
hosts = hosts.filter(attr == value) |
|
184 |
||
185 |
# render |
|
186 |
title = "DHCP Hosts: {value}".format(value=value) |
|
187 |
html = render_host(host, hosts) |
|
188 |
||
189 |
else : |
|
190 |
return Response("Not Found", status=404) |
|
191 |
||
192 |
# render |
|
193 |
html = web.render_layout(title, html) |
|
194 |
||
1
731d2df704f0
fixup index + non-chunked response (?) + hosts + evil hardcoded db url
Tero Marttila <terom@paivola.fi>
parents:
0
diff
changeset
|
195 |
return web.Response(html, content_type='text/html; charset=UTF-8') |
0 | 196 |