dont attempt to sync interface info every time the interfaces class is instantiated...
[sfa.git] / sfa / server / interface.py
1 #
2 ### $Id: interface.py 17583 2010-04-06 15:01:08Z tmack $
3 ### $URL: https://svn.planet-lab.org/svn/sfa/trunk/sfa/server/interface.py $
4 #
5
6
7 from sfa.util.faults import *
8 from sfa.util.storage import *
9 from sfa.util.namespace import *
10 from sfa.trust.gid import GID
11 from sfa.util.table import SfaTable
12 from sfa.util.record import SfaRecord
13 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
14 import sfa.util.soapprotocol as soapprotocol
15
16  
17 # GeniLight client support is optional
18 try:
19     from egeni.geniLight_client import *
20 except ImportError:
21     GeniClientLight = None            
22
23
24 ##
25 # In is a dictionary of registry connections keyed on the registry
26 # hrn
27
28 class Interfaces(dict):
29     """
30     Interfaces is a base class for managing information on the
31     peers we are federated with. It is responsible for the following:
32
33     1) Makes sure a record exist in the local registry for the each 
34        fedeated peer   
35     2) Attepts to fetch and install trusted gids   
36     3) Provides connections (xmlrpc or soap) to federated peers
37     """
38
39     # fields that must be specified in the config file
40     default_fields = {
41         'hrn': '',
42         'addr': '', 
43         'port': '', 
44     }
45
46     # defined by the class 
47     default_dict = {}
48
49     # allowed types
50     types = ['sa', 'ma']
51
52     def __init__(self, api, conf_file, type):
53         if type not in self.types:
54             raise SfaInfaildArgument('Invalid type %s: must be in %s' % (type, self.types))    
55         dict.__init__(self, {})
56         self.api = api
57         self.type = type  
58         # load config file
59         self.interface_info = XmlStorage(conf_file, self.default_dict)
60         self.interface_info.load()
61         self.interfaces = self.interface_info.values()[0].values()[0]
62         if not isinstance(self.interfaces, list):
63             self.interfaces = [self.interfaces]
64         # get connections
65         self.update(self.get_connections(self.interfaces))
66
67     def sync_interfaces(self):
68         """
69         Install missing trusted gids and db records for our federated
70         interfaces
71         """     
72         # Attempt to get any missing peer gids
73         # There should be a gid file in /etc/sfa/trusted_roots for every
74         # peer registry found in in the registries.xml config file. If there
75         # are any missing gids, request a new one from the peer registry.
76         gids_current = self.api.auth.trusted_cert_list
77         hrns_current = [gid.get_hrn() for gid in gids_current] 
78         hrns_expected = [interface['hrn'] for interface in self.interfaces] 
79         new_hrns = set(hrns_expected).difference(hrns_current)
80         self.get_peer_gids(new_hrns)
81
82         # update the local db records for these registries
83         self.update_db_records(self.type)
84         
85     def get_peer_gids(self, new_hrns):
86         """
87         Install trusted gids from the specified interfaces.  
88         """
89         if not new_hrns:
90             return
91         trusted_certs_dir = self.api.config.get_trustedroots_dir()
92         for new_hrn in new_hrns:
93             # the gid for this interface should already be installed  
94             if new_hrn == self.api.config.SFA_INTERFACE_HRN:
95                 continue
96             try:
97                 # get gid from the registry
98                 interface = self.get_connections(self.interfaces[new_hrn])[new_hrn]
99                 trusted_gids = interface.get_trusted_certs()
100                 # default message
101                 message = "interface: %s\tunable to install trusted gid for %s" % \
102                            (self.api.interface, new_hrn) 
103                 if trusted_gids:
104                     # the gid we want shoudl be the first one in the list, 
105                     # but lets make sure
106                     for trusted_gid in trusted_gids:
107                         gid = GID(string=trusted_gids[0])
108                         if gid.get_hrn() == new_hrn:
109                             gid_filename = os.path.join(trusted_certs_dir, '%s.gid' % new_hrn)
110                             gid.save_to_file(gid_filename, save_parents=True)
111                             message = "interface: %s\tinstalled trusted gid for %s" % \
112                                 (self.api.interface, new_hrn)
113                 # log the message
114                 self.api.logger.info(message)
115             except:
116                 message = "interface: %s\tunable to install trusted gid for %s" % \
117                             (self.api.interface, new_hrn) 
118                 self.api.logger.info(message)
119         
120         # reload the trusted certs list
121         self.api.auth.load_trusted_certs()
122
123     def update_db_records(self, type):
124         """
125         Make sure there is a record in the local db for allowed registries
126         defined in the config file (registries.xml). Removes old records from
127         the db.         
128         """
129         # get hrns we expect to find
130         hrns_expected = [interface['hrn'] for interface in self.interfaces]
131
132         # get hrns that actually exist in the db
133         table = SfaTable()
134         records = table.find({'type': type})
135         hrns_found = [record['hrn'] for record in records]
136        
137         # remove old records
138         for record in records:
139             if record['hrn'] not in hrns_expected:
140                 table.remove(record)
141
142         # add new records
143         for hrn in hrns_expected:
144             if hrn not in hrns_found:
145                 record = {
146                     'hrn': hrn,
147                     'type': type,
148                     'pointer': -1, 
149                     'authority': get_authority(hrn),
150                 }
151                 record = SfaRecord(dict=record)
152                 table.insert(record)
153                         
154  
155     def get_connections(self, interfaces):
156         """
157         read connection details for the trusted peer registries from file return 
158         a dictionary of connections keyed on interface hrn. 
159         """
160         connections = {}
161         required_fields = self.default_fields.keys()
162         if not isinstance(interfaces, list):
163             interfaces = [interfaces]
164         for interface in interfaces:
165             # make sure the required fields are present and not null
166             for key in required_fields:
167                 if not interface.get(key):
168                     continue 
169             hrn, address, port = interface['hrn'], interface['addr'], interface['port']
170             url = 'http://%(address)s:%(port)s' % locals()
171             # check which client we should use
172             # sfa.util.xmlrpcprotocol is default
173             client_type = 'xmlrpcprotocol'
174             if interface.has_key('client') and \
175                interface['client'] in ['geniclientlight'] and \
176                GeniClientLight:
177                 client_type = 'geniclientlight'
178                 connections[hrn] = GeniClientLight(url, self.api.key_file, self.api.cert_file) 
179             else:
180                 connections[hrn] = xmlrpcprotocol.get_server(url, self.api.key_file, self.api.cert_file)
181
182         return connections