Merge branch 'newinterface' of ssh://bakers@git.planet-lab.org/git/plcapi into newint...
[plcapi.git] / PLC / Routes.py
1 #
2 # Functions for interacting with the routes table in the database
3 #
4
5 from types import StringTypes
6 import socket
7 import struct
8
9 from PLC.Faults import *
10 from PLC.Parameter import Parameter
11 from PLC.Filter import Filter
12 from PLC.Debug import profile
13 from PLC.Table import Row, Table
14 from PLC.NetworkTypes import NetworkType, NetworkTypes
15 from PLC.NetworkMethods import NetworkMethod, NetworkMethods
16 from PLC.IpAddresses import SimpleAddress, Subnet
17 import PLC.Nodes
18
19 class Route(Row):
20     """
21     Representation of a row in the routees table. To use, optionally
22     instantiate with a dict of values. Update as you would a
23     dict. Commit to the database with sync().
24     """
25
26     table_name = 'routes'
27     primary_key = 'route_id'
28     join_tables = []
29     fields = {
30         'route_id': Parameter(int, "Route identifier"),
31         'node_id': Parameter(int, "Node this route belongs to"),
32         'subnet': Parameter(str, "Subnet for this route", nullok = True),
33         'next_hop': Parameter(str, "IP address to send outgoing traffic"),
34         'interface_id': Parameter(int, "Interface to send outgoing traffic"),
35         'last_updated': Parameter(int, "Date and time when node entry was created", ro = True),
36         }
37
38     tags = {}
39
40     # TODO - validate next_hop and subnet
41
42     def validate_node_id(self, node_id):
43         nodes = PLC.Nodes.Nodes(self.api, [node_id])
44         if not nodes:
45             raise PLCInvalidArgument, "No such node %d"%node_id
46
47         return node_id
48
49     def validate_interface_id(self, interface_id):
50         interfaces = PLC.Interfaces.Interfaces(self.api, [interface_id])
51         if not interfaces:
52             raise PLCInvalidArgument, "No such interface %d"%interface_id
53
54         if (interfaces[0]["node_id"] != self["node_id"]):
55             raise PLCInvalidArgument, "Interface is not for the same node as this route"
56
57         return interface_id
58
59     def validate_subnet(self, subnet):
60         Subnet(subnet)
61         return subnet
62
63     def validate_next_hop(self, next_hop):
64         SimpleAddress(next_hop)
65         return next_hop
66
67     def validate(self):
68         """
69         Flush changes back to the database.
70         """
71
72         # Basic validation
73         Row.validate(self)
74
75     validate_last_updated = Row.validate_timestamp
76
77     def update_timestamp(self, col_name, commit = True):
78         """
79         Update col_name field with current time
80         """
81
82         assert 'route_id' in self
83         assert self.table_name
84
85         self.api.db.do("UPDATE %s SET %s = CURRENT_TIMESTAMP " % (self.table_name, col_name) + \
86                        " where route_id = %d" % (self['route_id']) )
87         self.sync(commit)
88
89     def update_last_updated(self, commit = True):
90         self.update_timestamp('last_updated', commit)
91
92 class Routes(Table):
93     """
94     Representation of row(s) from the routees table in the
95     database.
96     """
97
98     def __init__(self, api, route_filter = None, columns = None):
99         Table.__init__(self, api, Route, columns)
100
101         # the view that we're selecting upon: start with view_nodes
102         view = "view_routes"
103         # as many left joins as requested tags
104         for tagname in self.tag_columns:
105             view= "%s left join %s using (%s)"%(view,Route.tagvalue_view_name(tagname),
106                                                 Route.primary_key)
107
108         sql = "SELECT %s FROM %s WHERE True" % \
109             (", ".join(self.columns.keys()+self.tag_columns.keys()),view)
110
111         if route_filter is not None:
112             if isinstance(route_filter, (list, tuple, set)):
113                 # Separate the list into integers and strings
114                 ints = filter(lambda x: isinstance(x, (int, long)), route_filter)
115                 route_filter = Filter(Route.fields, {'route_id': ints})
116                 sql += " AND (%s) %s" % route_filter.sql(api, "OR")
117             elif isinstance(route_filter, dict):
118                 allowed_fields=dict(Route.fields.items()+Route.tags.items())
119                 route_filter = Filter(allowed_fields, route_filter)
120                 sql += " AND (%s) %s" % route_filter.sql(api)
121             elif isinstance(route_filter, int):
122                 route_filter = Filter(Route.fields, {'route_id': [route_filter]})
123                 sql += " AND (%s) %s" % route_filter.sql(api)
124             else:
125                 raise PLCInvalidArgument, "Wrong route filter %r"%route_filter
126
127         self.selectall(sql)