2 # Functions for interacting with the interfaces table in the database
4 # Mark Huang <mlhuang@cs.princeton.edu>
5 # Copyright (C) 2006 The Trustees of Princeton University
8 from types import StringTypes
12 from PLC.Faults import *
13 from PLC.Parameter import Parameter
14 from PLC.Filter import Filter
15 from PLC.Debug import profile
16 from PLC.Table import Row, Table
17 from PLC.NetworkTypes import NetworkType, NetworkTypes
18 from PLC.NetworkMethods import NetworkMethod, NetworkMethods
23 ip = socket.inet_ntoa(socket.inet_aton(ip))
28 def in_same_network(address1, address2, netmask):
30 Returns True if two IPv4 addresses are in the same network. Faults
31 if an address is invalid.
34 address1 = struct.unpack('>L', socket.inet_aton(address1))[0]
35 address2 = struct.unpack('>L', socket.inet_aton(address2))[0]
36 netmask = struct.unpack('>L', socket.inet_aton(netmask))[0]
38 return (address1 & netmask) == (address2 & netmask)
42 Representation of a row in the interfaces table. To use, optionally
43 instantiate with a dict of values. Update as you would a
44 dict. Commit to the database with sync().
47 table_name = 'interfaces'
48 primary_key = 'interface_id'
49 join_tables = ['interface_tag', 'ip_addresses', 'routes']
51 'interface_id': Parameter(int, "Node interface identifier"),
52 'method': Parameter(str, "Addressing method (e.g., 'static' or 'dhcp')"),
53 'mac': Parameter(str, "MAC address", nullok = True),
54 'bwlimit': Parameter(int, "Bandwidth limit", min = 0, nullok = True),
55 'hostname': Parameter(str, "(Optional) Hostname", nullok = True),
56 'node_id': Parameter(int, "Node associated with this interface"),
57 'is_primary': Parameter(bool, "Is the primary interface for this node"),
58 'if_name': Parameter(str, "Interface name", nullok = True),
59 'interface_tag_ids' : Parameter([int], "List of interface settings"),
60 'ip_address_ids': Parameter([int], "List of addresses"),
61 'last_updated': Parameter(int, "Date and time when node entry was created", ro = True),
64 view_tags_name = "view_interface_tags"
67 def validate_method(self, method):
68 network_methods = [row['method'] for row in NetworkMethods(self.api)]
69 if method not in network_methods:
70 raise PLCInvalidArgument, "Invalid addressing method %s"%method
73 def validate_mac(self, mac):
78 bytes = mac.split(":")
81 for i, byte in enumerate(bytes):
83 if byte < 0 or byte > 255:
85 bytes[i] = "%02x" % byte
88 raise PLCInvalidArgument, "Invalid MAC address %s"%mac
92 def validate_bwlimit(self, bwlimit):
97 raise PLCInvalidArgument, 'Minimum bw is 1 Mbps'
99 if bwlimit >= 1000000:
100 raise PLCInvalidArgument, 'Maximum bw must be less than 1000000'
104 def validate_hostname(self, hostname):
109 if not PLC.Nodes.valid_hostname(hostname):
110 raise PLCInvalidArgument, "Invalid hostname %s"%hostname
114 def validate_node_id(self, node_id):
115 nodes = PLC.Nodes.Nodes(self.api, [node_id])
117 raise PLCInvalidArgument, "No such node %d"%node_id
121 def validate_is_primary(self, is_primary):
123 Set this interface to be the primary one.
127 nodes = PLC.Nodes.Nodes(self.api, [self['node_id']])
129 raise PLCInvalidArgument, "No such node %d"%node_id
132 if node['interface_ids']:
133 conflicts = Interfaces(self.api, node['interface_ids'])
134 for interface in conflicts:
135 if ('interface_id' not in self or \
136 self['interface_id'] != interface['interface_id']) and \
137 interface['is_primary']:
138 raise PLCInvalidArgument, "Can only set one primary interface per node"
144 Flush changes back to the database.
150 assert 'method' in self
151 method = self['method']
153 validate_last_updated = Row.validate_timestamp
155 def update_timestamp(self, col_name, commit = True):
157 Update col_name field with current time
160 assert 'interface_id' in self
161 assert self.table_name
163 self.api.db.do("UPDATE %s SET %s = CURRENT_TIMESTAMP " % (self.table_name, col_name) + \
164 " where interface_id = %d" % (self['interface_id']) )
167 def update_last_updated(self, commit = True):
168 self.update_timestamp('last_updated', commit)
170 def delete(self,commit=True):
171 ### need to cleanup ilinks
172 self.api.db.do("DELETE FROM ilink WHERE src_interface_id=%d OR dst_interface_id=%d" % \
173 (self['interface_id'],self['interface_id']))
177 class Interfaces(Table):
179 Representation of row(s) from the interfaces table in the
183 def __init__(self, api, interface_filter = None, columns = None):
184 Table.__init__(self, api, Interface, columns)
186 # the view that we're selecting upon: start with view_nodes
187 view = "view_interfaces"
188 # as many left joins as requested tags
189 for tagname in self.tag_columns:
190 view= "%s left join %s using (%s)"%(view,Interface.tagvalue_view_name(tagname),
191 Interface.primary_key)
193 sql = "SELECT %s FROM %s WHERE True" % \
194 (", ".join(self.columns.keys()+self.tag_columns.keys()),view)
196 if interface_filter is not None:
197 # TODO: Deleted the ability here to filter by ipaddress; Need to make
198 # sure that wasn't used anywhere.
199 if isinstance(interface_filter, (list, tuple, set)):
200 # Separate the list into integers and strings
201 ints = filter(lambda x: isinstance(x, (int, long)), interface_filter)
202 interface_filter = Filter(Interface.fields, {'interface_id': ints})
203 sql += " AND (%s) %s" % interface_filter.sql(api, "OR")
204 elif isinstance(interface_filter, dict):
205 allowed_fields=dict(Interface.fields.items()+Interface.tags.items())
206 interface_filter = Filter(allowed_fields, interface_filter)
207 sql += " AND (%s) %s" % interface_filter.sql(api)
208 elif isinstance(interface_filter, int):
209 interface_filter = Filter(Interface.fields, {'interface_id': [interface_filter]})
210 sql += " AND (%s) %s" % interface_filter.sql(api)
212 raise PLCInvalidArgument, "Wrong interface filter %r"%interface_filter