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
24 from PLC.PyCurl import PyCurlTransport
25 from PLC.GPG import gpg_sign
29 Stores the list of peering PLCs in the peers table.
30 See the Row class for more details
34 primary_key = 'peer_id'
36 'peer_id': Parameter (int, "Peer identifier"),
37 'peername': Parameter (str, "Peer name"),
38 'peer_url': Parameter (str, "Peer API URL"),
39 'key': Parameter(str, "Peer GPG public key"),
40 'cacert': Parameter(str, "Peer SSL public certificate"),
42 'site_ids': Parameter([int], "List of sites for this peer is authoritative"),
43 'person_ids': Parameter([int], "List of users for this peer is authoritative"),
44 'key_ids': Parameter([int], "List of keys for which this peer is authoritative"),
45 'node_ids': Parameter([int], "List of nodes for which this peer is authoritative"),
46 'attribute_type_ids': Parameter([int], "List of slice attribute types for which this peer is authoritative"),
47 'slice_attribute_ids': Parameter([int], "List of slice attributes for which this peer is authoritative"),
48 'slice_ids': Parameter([int], "List of slices for which this peer is authoritative"),
51 def validate_peer_url(self, url):
53 Validate URL. Must be HTTPS.
56 (scheme, netloc, path, params, query, fragment) = urlparse(url)
58 raise PLCInvalidArgument, "Peer URL scheme must be https"
62 def delete(self, commit = True):
64 Deletes this peer and all related entities.
67 assert 'peer_id' in self
69 # Remove all related entities
71 Sites(self.api, self['site_ids']) + \
72 Persons(self.api, self['person_ids']) + \
73 Keys(self.api, self['key_ids']) + \
74 Nodes(self.api, self['node_ids']) + \
75 SliceAttributeTypes(self.api, self['attribute_type_ids']) + \
76 SliceAttributes(self.api, self['slice_attribute_ids']) + \
77 Slices(self.api, self['slice_ids']):
78 assert obj['peer_id'] == self['peer_id']
79 obj.delete(commit = False)
82 self['deleted'] = True
85 def connect(self, **kwds):
87 Connect to this peer via XML-RPC.
90 self.server = xmlrpclib.ServerProxy(self['peer_url'],
91 PyCurlTransport(self['peer_url'], self['cacert']),
92 allow_none = 1, **kwds)
94 def add_auth(self, function, methodname, **kwds):
96 Sign the specified XML-RPC call and add an auth struct as the
97 first argument of the call.
100 def wrapper(*args, **kwds):
101 signature = gpg_sign(methodname, args,
102 self.api.config.PLC_ROOT_GPG_KEY,
103 self.api.config.PLC_ROOT_GPG_KEY_PUB)
105 auth = {'AuthMethod': "gpg",
106 'name': self.api.config.PLC_NAME,
107 'signature': signature}
109 # Automagically add auth struct to every call
110 args = (auth,) + args
112 return function(*args)
116 def __getattr__(self, methodname):
118 Fetch a callable for the specified method.
121 function = getattr(self.server, methodname)
124 # Figure out if the function is a PLCAPI function and
125 # requires an authentication structure as its first
127 api_function = self.api.callable(methodname)
128 if api_function.accepts and \
129 (isinstance(api_function.accepts[0], PLC.Auth.Auth) or \
130 (isinstance(api_function.accepts[0], Mixed) and \
131 filter(lambda param: isinstance(param, Auth), func.accepts[0]))):
132 function = self.add_auth(function, methodname)
133 except Exception, err:
140 Maps to the peers table in the database
143 def __init__ (self, api, peer_filter = None, columns = None):
144 Table.__init__(self, api, Peer, columns)
146 sql = "SELECT %s FROM view_peers WHERE deleted IS False" % \
147 ", ".join(self.columns)
149 if peer_filter is not None:
150 if isinstance(peer_filter, (list, tuple, set)):
151 # Separate the list into integers and strings
152 ints = filter(lambda x: isinstance(x, (int, long)), peer_filter)
153 strs = filter(lambda x: isinstance(x, StringTypes), peer_filter)
154 peer_filter = Filter(Peer.fields, {'peer_id': ints, 'peername': strs})
155 sql += " AND (%s)" % peer_filter.sql(api, "OR")
156 elif isinstance(peer_filter, dict):
157 peer_filter = Filter(Peer.fields, peer_filter)
158 sql += " AND (%s)" % peer_filter.sql(api, "AND")