root/mirror/edenwall/nulog2/branches/2.0/doc/tables.rst
| Revision 6513, 7.3 kB (checked in by romain, 3 years ago) | |
|---|---|
|
|
Adding a table
I. Backend
All operations will be in nulog-core/ directory.
1.1 Creating a Table class
1.1.1 Init
Open table.py to create a new class inherited from TableBase:
class ExampleTable(TableBase):
def __init__(self):
pass
You may call the TableBase constructor and give it a dict object.
In this dict there are the following values:
names: list of column names. It will be displayed in a graphical array.
sort: in the same order, to know on which SQL column name it may sort. Note that it MUST be the SQL names.
links: Tell what an item on the array will point to. This is a list of dicts. Each column must have a dict with these values:
- function: used by the frontend to know what function to call.
- argument-value pairs passed to the function. If an argument hasn't any value (None), it will be replaced by cell value.
I think it isn't clear in your mind, so an example is appropriate:
def __init__(self):
TableBase.__init__(self,
{'names': ['User', 'Packets', 'Last packet'],
'sort': ['username', 'packets', 'end'],
'links': [{'function': 'PacketTable', # Function to call
'proto': 'tcp', 'username': None}, # Args and
# values to pass the function to call
None,
None]
})
self.args = {'sortby': 'packets',
'sort': 'DESC',
'limit': 30,
'start': 0}
Table has three columns, User, Packets and Last packet. SQL column names are username, packets and end.
When you will click on a username, the next page will show the packet list from user username.
You can notice that there is an args attribute which is declared as a dict. It contains default arguments. You can put any argument you want, you will use it yourself.
1.1.2 Call
When your ExampleTable is used, the __call__() function will be called.
This function receives arguments requested by your object. You can build you request with it.
To define what arguments you can receive, and how to check if they are valid, you have these functions:
self._arg_int(args, key): Check if args[key] is an integer, and add it to self.args dict.
self._arg_in(args, key, list): Check if args[key] is in list (a tuple), and add it to self.args.
self._arg_where(args, buffer, list): To create the where instruction, you have to pass a StringIO object as buffer variable to save in string. list is a dict where keys are args keys, and values are help functions. The following functions are available:
- self._arg_where_ip to create a filter on ip. [1]
- self._arg_where_ip_both , like self._arg_where_ip but it will check for source and destination ips.
- self._arg_where_port to create a filter on port. [1]
- self._arg_where_proto to create a filter on protocol.
- self._arg_where_state to create a filter on packet state. [1]
| [1] | (1, 2, 3) These functions depend of key string. For example, _arg_where_port will create key = value string. |
Here is an example:
def __call__(self, **args):
where = StringIO()
# In our example, we want to display the number of dropped packets for users in the last 15 minutes
where.write('WHERE timestamp > NOW()- INTERVAL 15 MINUTE AND (state IS NULL OR state = 0)')
self._arg_int(args, 'limit')
self._arg_int(args, 'start')
self._arg_in (args, 'sortby', ('username', 'packets', 'end'))
self._arg_in (args, 'sort', ('DESC', 'ASC'))
self._arg_where(args, where, {'sport': self._arg_where_port,
'dport': self._arg_where_port,
'proto': self._arg_where_proto
})
Now we must call a function to run the SQL query.
An objet is used for that. It is self.dbpool which abstract all SQL queries. You will have to create a method of this object to request SQL, but we'll see it later.
Call this method with args:
result = self.dbpool.select_example(where.getvalue(), self.args['sortby'], self.args['sort'],
self.args['start'], self.args['limit'])
result.addCallback(self._print_result)
return result
self._print_result is a callback of TableBase. For each line it will call a function self.entry_form, empty on TableBase. But you can overload it like this:
def entry_form(self, entry):
return (entry[0], entry[1], entry[2])
In our example, there isn't any treatment to do, but you can modify an entry. For example an IP is an integer (ipv4) or a byte (ipv6) in the SQL table. You probably want to convert it to a human-readable IP. You could call self.ip2str() function to do this. See TabeBase's API.
1.2 Create a method on dbpool object
Go to inl.py.
There is a base object for the standard ulog database named DataBase. Derived objects are used for other SQL schemas, for example TriggerDataBase.
You have to add your method like this:
def select_example(self, where, sortby, sort, start, limit):
return self._sql_query("""SELECT username, COUNT(*) AS packets, MAX(timestamp) AS end
FROM ulog
WHERE %s
GROUP BY username
ORDER BY %s %s
LIMIT %d,%d""" % (where, sortby, sort, start, limit))
Now, if you have any optimization to do on another schema, you can add the same method with another query in another class.
1.3 Reference an object
Go to the end of the file table.py, in function table(). You'll see these lines:
tables = {
'TCPTable': TCPTable,
'UDPTable': UDPTable,
'IpTable': IpTable,
'UserTable': UserTable,
'PacketTable': PacketTable,
'ConUserTable': ConUserTable,
'PacketInfo': info.PacketInfo
}
You can add this in this dict:
'ExampleTable': ExampleTable,
That's all!
II. Frontend
2.1 Nothing?????
Nothing!
Yes, there is nothing to do on frontend (nulog-web).
You can go to your new table at http://localhost:8080/nulog/ExampleTable/
2.2 But you can do something
For example, if you want to put your new table on indexpage, the only thing you have to do is to go into nulog-web/nulog.py and to modify this line, for example:
frag = FragmentFactory(ctx, 'table', 'UserTable', _('Top User connections:'), 'user.gif', switch=True)
and replace it with this line:
frag = FragmentFactory(ctx, 'table', 'ExampleTable', _('Top 15min last user connections:'), 'user.gif', switch=True)
2.2.1 Graphs?
For example, you can force a pie show by replacing 'table' with 'pie', and remove switch=True.
See all params of FragmentFactory's function.
III. Conclusion
You can easily add a table on Nulog2!
