pvl/verkko/hosts.py
changeset 19 4e2e26f4d058
parent 17 29f0cf9220e0
child 20 790e78bed63e
equal deleted inserted replaced
18:2d16489b8782 19:4e2e26f4d058
   189             
   189             
   190             yield html.span("Page {page} of {pages}".format(page=(page + 1), pages=(pages or '???')))
   190             yield html.span("Page {page} of {pages}".format(page=(page + 1), pages=(pages or '???')))
   191 
   191 
   192             yield html.a(href=url(page=(page + 1)))(html("» Next"))
   192             yield html.a(href=url(page=(page + 1)))(html("» Next"))
   193 
   193 
       
   194         def render_filter (filter) :
       
   195             value = filters.get(filter)
       
   196 
       
   197             if value :
       
   198                 # XXX: multi-valued filters?
       
   199                 value = value[0]
       
   200             else :
       
   201                 value = None
       
   202 
       
   203             return html.input(type='text', name=filter, value=value)
   194 
   204 
   195         table = html.table(
   205         table = html.table(
   196             html.caption(title) if title else None,
   206             html.caption(title) if title else None,
   197             html.thead(
   207             html.thead(
   198                 html.tr(
   208                 html.tr(
   207                     html.td(
   217                     html.td(
   208                         html.input(type='submit', value=u'\u00BF'),
   218                         html.input(type='submit', value=u'\u00BF'),
   209                     ),
   219                     ),
   210                     (
   220                     (
   211                         html.td(class_=class_)(
   221                         html.td(class_=class_)(
   212                             html.input(type='text', name=filter, value=filters.get(filter)) if filter else None
   222                             render_filter(filter) if filter else None
   213                         ) for title, sort, filter, class_ in COLS
   223                         ) for title, sort, filter, class_ in COLS
   214                     )
   224                     )
   215                 ) if filters is not False else None
   225                 ) if filters is not False else None
   216             ),
   226             ),
   217             html.tbody(
   227             html.tbody(
   302 
   312 
   303 class ListHandler (BaseHandler) :
   313 class ListHandler (BaseHandler) :
   304     # pagination
   314     # pagination
   305     PAGE = 10
   315     PAGE = 10
   306 
   316 
       
   317     # views
       
   318     VIEWS = (
       
   319         ("Last hour",   dict(seen='1h')),
       
   320         ("Last day",    dict(seen='24h')),
       
   321         ("All",         dict()),
       
   322     ) + tuple(
       
   323         ("Network " + network,          dict(ip=network)) for network in (
       
   324             '194.197.235.0/24',
       
   325             '10.1.0.0/16',
       
   326             '10.4.0.0/16',
       
   327             '10.5.0.0/16',
       
   328             '10.6.0.0/16',
       
   329             '10.10.0.0/16',
       
   330         )
       
   331     ) + (
       
   332         ("Valid",       dict(state=('DHCPACK', 'DHCPRELEASE'))),
       
   333         ("Incomplete",  dict(state=('DHCPDISCOVER', 'DHCPOFFER', 'DHCPREQUEST'))),
       
   334         ("Invalid",     dict(state=('DHCPNAK', ))),
       
   335     )
       
   336 
       
   337     def filter (self, attr, value) :
       
   338         """
       
   339             Return filter expression for given attr == value
       
   340         """
       
   341 
       
   342         if attr == 'seen' :
       
   343             column = Host.last_seen
       
   344 
       
   345             if value.isdigit() :
       
   346                 # specific date
       
   347                 date = datetime.datetime.strptime(value, Host.DATE_FMT).date()
       
   348 
       
   349                 return db.between(date.strftime(Host.DATE_FMT), 
       
   350                         db.func.strftime(Host.DATE_FMT, Host.first_seen),
       
   351                         db.func.strftime(Host.DATE_FMT, Host.last_seen)
       
   352                 )
       
   353             else :
       
   354                 # recent
       
   355                 timedelta = parse_timedelta(value)
       
   356                 
       
   357                 return ((db.func.now() - Host.last_seen) < timedelta)
       
   358 
       
   359                 # XXX: for sqlite, pgsql should handle this natively?
       
   360                 # to seconds
       
   361                 #timeout = timedelta.days * (24 * 60 * 60) + timedelta.seconds
       
   362                 
       
   363                 # WHERE strftime('%s', 'now') - strftime('%s', last_seen) < :timeout
       
   364                 #filter = (db.func.strftime('%s', 'now') - db.func.strftime('%s', Host.last_seen) < timeout)
       
   365         
       
   366         elif attr == 'ip' :
       
   367             column = Host.ip
       
   368 
       
   369             # column is IPv4 string literal format...
       
   370             if '/' in value :
       
   371                 return (db.func.inet(Host.ip).op('<<')(db.func.cidr(value)))
       
   372             else :
       
   373                 return (db.func.inet(Host.ip) == db.func.inet(value))
       
   374 
       
   375         else :
       
   376             # preprocess
       
   377             like = False
       
   378 
       
   379             if value.endswith('*') :
       
   380                 like = value.replace('*', '%')
       
   381 
       
   382             elif attr == 'mac' :
       
   383                 value = Host.normalize_mac(value)
       
   384 
       
   385             # filter
       
   386             column = self.HOST_ATTRS[attr]
       
   387 
       
   388             if like :
       
   389                 return (column.like(like))
       
   390             else :
       
   391                 return (column == value)
       
   392 
   307     def process (self) :
   393     def process (self) :
   308         hosts = self.query()
   394         hosts = self.query()
   309 
   395 
   310         # filter?
   396         # filter?
   311         column = None
       
   312         self.filters = {}
   397         self.filters = {}
   313 
   398 
   314         for attr in self.HOST_ATTRS :
   399         for attr in self.HOST_ATTRS :
   315             value = self.request.args.get(attr)
   400             values = self.request.args.getlist(attr)
   316 
   401 
   317             if not value :
   402             if not values :
   318                 continue
   403                 continue
   319 
       
   320             if attr == 'seen' :
       
   321                 column = Host.last_seen
       
   322 
       
   323                 if value.isdigit() :
       
   324                     # specific date
       
   325                     date = datetime.datetime.strptime(value, Host.DATE_FMT).date()
       
   326 
       
   327                     filter = db.between(date.strftime(Host.DATE_FMT), 
       
   328                             db.func.strftime(Host.DATE_FMT, Host.first_seen),
       
   329                             db.func.strftime(Host.DATE_FMT, Host.last_seen)
       
   330                     )
       
   331                 else :
       
   332                     # recent
       
   333                     timedelta = parse_timedelta(value)
       
   334                     
       
   335                     filter = ((db.func.now() - Host.last_seen) < timedelta)
       
   336 
       
   337                     # XXX: for sqlite, pgsql should handle this natively?
       
   338                     # to seconds
       
   339                     #timeout = timedelta.days * (24 * 60 * 60) + timedelta.seconds
       
   340                     
       
   341                     # WHERE strftime('%s', 'now') - strftime('%s', last_seen) < :timeout
       
   342                     #filter = (db.func.strftime('%s', 'now') - db.func.strftime('%s', Host.last_seen) < timeout)
       
   343             
   404             
   344             elif attr == 'ip' :
   405             filter = db.or_(*[self.filter(attr, value) for value in values])
   345                 column = Host.ip
   406 
   346 
   407             log.debug("filter %s: %s", attr, filter)
   347                 # column is IPv4 string literal format...
   408 
   348                 if '/' in value :
       
   349                     filter = (db.func.inet(Host.ip).op('<<')(db.func.cidr(value)))
       
   350                 else :
       
   351                     filter = (db.func.inet(Host.ip) == db.func.inet(value))
       
   352 
       
   353             else :
       
   354                 # preprocess
       
   355                 like = False
       
   356 
       
   357                 if value.endswith('*') :
       
   358                     like = value.replace('*', '%')
       
   359 
       
   360                 elif attr == 'mac' :
       
   361                     value = Host.normalize_mac(value)
       
   362 
       
   363                 # filter
       
   364                 column = self.HOST_ATTRS[attr]
       
   365 
       
   366                 if like :
       
   367                     filter = (column.like(like))
       
   368                 else :
       
   369                     filter = (column == value)
       
   370             
       
   371             hosts = hosts.filter(filter)
   409             hosts = hosts.filter(filter)
   372             self.filters[attr] = value
   410             self.filters[attr] = values
   373 
   411 
   374         # sort XXX: default per filter column
   412         # sort XXX: default per filter column?
   375         hosts = self.sort(hosts) #, column)
   413         hosts = self.sort(hosts)
   376         
   414         
   377         # page?
   415         # page?
   378         self.page = self.request.args.get('page')
   416         self.page = self.request.args.get('page')
   379 
   417 
   380         if self.page :
   418         if self.page :
   384 
   422 
   385         self.hosts = hosts
   423         self.hosts = hosts
   386 
   424 
   387     def title (self) :
   425     def title (self) :
   388         if self.filters :
   426         if self.filters :
   389             return "DHCP Hosts: {filters}".format(filters=', '.join(self.filters.itervalues()))
   427             return "DHCP Hosts: {filters}".format(filters=', '.join(value for values in self.filters.itervalues() for value in values))
   390         else :
   428         else :
   391             return "DHCP Hosts"
   429             return "DHCP Hosts"
   392     
   430     
   393     def render (self) :
   431     def render (self) :
   394         return (
   432         return (