2 # Thierry Parmentelat - INRIA
6 from types import StringTypes
7 from urlparse import urlparse
9 from PLC.Faults import *
10 from PLC.Parameter import Parameter, Mixed
11 from PLC.Filter import Filter
12 from PLC.Table import Row, Table
15 from PLC.Sites import Site, Sites
16 from PLC.Persons import Person, Persons
17 from PLC.Keys import Key, Keys
18 from PLC.Nodes import Node, Nodes
19 from PLC.SliceAttributeTypes import SliceAttributeType, SliceAttributeTypes
20 from PLC.SliceAttributes import SliceAttribute, SliceAttributes
21 from PLC.Slices import Slice, Slices
25 Stores the list of peering PLCs in the peers table.
26 See the Row class for more details
30 primary_key = 'peer_id'
32 'peer_id': Parameter (int, "Peer identifier"),
33 'peername': Parameter (str, "Peer name"),
34 'peer_url': Parameter (str, "Peer API URL"),
35 'key': Parameter(str, "Peer GPG public key"),
36 'cacert': Parameter(str, "Peer SSL public certificate"),
38 'site_ids': Parameter([int], "List of sites for this peer is authoritative"),
39 'person_ids': Parameter([int], "List of users for this peer is authoritative"),
40 'key_ids': Parameter([int], "List of keys for which this peer is authoritative"),
41 'node_ids': Parameter([int], "List of nodes for which this peer is authoritative"),
42 'attribute_type_ids': Parameter([int], "List of slice attribute types for which this peer is authoritative"),
43 'slice_attribute_ids': Parameter([int], "List of slice attributes for which this peer is authoritative"),
44 'slice_ids': Parameter([int], "List of slices for which this peer is authoritative"),
47 def validate_peer_url(self, url):
49 Validate URL. Must be HTTPS.
52 (scheme, netloc, path, params, query, fragment) = urlparse(url)
54 raise PLCInvalidArgument, "Peer URL scheme must be https"
58 def delete(self, commit = True):
60 Deletes this peer and all related entities.
63 assert 'peer_id' in self
65 # Remove all related entities
67 Sites(self.api, self['site_ids']) + \
68 Persons(self.api, self['person_ids']) + \
69 Keys(self.api, self['key_ids']) + \
70 Nodes(self.api, self['node_ids']) + \
71 SliceAttributeTypes(self.api, self['attribute_type_ids']) + \
72 SliceAttributes(self.api, self['slice_attribute_ids']) + \
73 Slices(self.api, self['slice_ids']):
74 assert obj['peer_id'] == self['peer_id']
75 obj.delete(commit = False)
78 self['deleted'] = True
81 def connect(self, **kwds):
83 Connect to this peer via XML-RPC.
87 from PLC.PyCurl import PyCurlTransport
88 self.server = xmlrpclib.ServerProxy(self['peer_url'],
89 PyCurlTransport(self['peer_url'], self['cacert']),
90 allow_none = 1, **kwds)
92 def add_auth(self, function, methodname, **kwds):
94 Sign the specified XML-RPC call and add an auth struct as the
95 first argument of the call.
98 def wrapper(*args, **kwds):
99 from PLC.GPG import gpg_sign
100 signature = gpg_sign(methodname, args,
101 self.api.config.PLC_ROOT_GPG_KEY,
102 self.api.config.PLC_ROOT_GPG_KEY_PUB)
104 auth = {'AuthMethod': "gpg",
105 'name': self.api.config.PLC_NAME,
106 'signature': signature}
108 # Automagically add auth struct to every call
109 args = (auth,) + args
111 return function(*args)
115 def __getattr__(self, methodname):
117 Fetch a callable for the specified method.
120 function = getattr(self.server, methodname)
123 # Figure out if the function is a PLCAPI function and
124 # requires an authentication structure as its first
126 api_function = self.api.callable(methodname)
127 if api_function.accepts and \
128 (isinstance(api_function.accepts[0], PLC.Auth.Auth) or \
129 (isinstance(api_function.accepts[0], Mixed) and \
130 filter(lambda param: isinstance(param, Auth), func.accepts[0]))):
131 function = self.add_auth(function, methodname)
132 except Exception, err:
139 Maps to the peers table in the database
142 def __init__ (self, api, peer_filter = None, columns = None):
143 Table.__init__(self, api, Peer, columns)
145 sql = "SELECT %s FROM view_peers WHERE deleted IS False" % \
146 ", ".join(self.columns)
148 if peer_filter is not None:
149 if isinstance(peer_filter, (list, tuple, set)):
150 # Separate the list into integers and strings
151 ints = filter(lambda x: isinstance(x, (int, long)), peer_filter)
152 strs = filter(lambda x: isinstance(x, StringTypes), peer_filter)
153 peer_filter = Filter(Peer.fields, {'peer_id': ints, 'peername': strs})
154 sql += " AND (%s)" % peer_filter.sql(api, "OR")
155 elif isinstance(peer_filter, dict):
156 peer_filter = Filter(Peer.fields, peer_filter)
157 sql += " AND (%s)" % peer_filter.sql(api, "AND")