use authority instead of sa, ma when defining authority type
[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 from sfa.util.faults import *
7 from sfa.util.storage import *
8 from sfa.util.namespace import *
9 from sfa.trust.gid import GID
10 from sfa.util.table import SfaTable
11 from sfa.util.record import SfaRecord
12 import traceback
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     types = ['authority']
50
51     def __init__(self, api, conf_file, type='authority'):
52         if type not in self.types:
53             raise SfaInfaildArgument('Invalid type %s: must be in %s' % (type, self.types))    
54         dict.__init__(self, {})
55         self.api = api
56         self.type = type  
57         # load config file
58         self.interface_info = XmlStorage(conf_file, self.default_dict)
59         self.interface_info.load()
60         interfaces = self.interface_info.values()[0].values()[0]
61         if not isinstance(interfaces, list):
62             interfaces = [self.interfaces]
63         self.interfaces = {}
64         for interface in interfaces:
65             self.interfaces[interface['hrn']] = interface
66
67
68     def sync_interfaces(self):
69         """
70         Install missing trusted gids and db records for our federated
71         interfaces
72         """     
73         # Attempt to get any missing peer gids
74         # There should be a gid file in /etc/sfa/trusted_roots for every
75         # peer registry found in in the registries.xml config file. If there
76         # are any missing gids, request a new one from the peer registry.
77         gids_current = self.api.auth.trusted_cert_list
78         hrns_current = [gid.get_hrn() for gid in gids_current] 
79         hrns_expected = self.interfaces.keys() 
80         new_hrns = set(hrns_expected).difference(hrns_current)
81         gids = self.get_peer_gids(new_hrns)
82         # update the local db records for these registries
83         self.update_db_records(self.type, gids)
84         
85     def get_peer_gids(self, new_hrns):
86         """
87         Install trusted gids from the specified interfaces.  
88         """
89         peer_gids = []
90         if not new_hrns:
91             return peer_gids
92         trusted_certs_dir = self.api.config.get_trustedroots_dir()
93         for new_hrn in new_hrns:
94             # the gid for this interface should already be installed  
95             if new_hrn == self.api.config.SFA_INTERFACE_HRN:
96                 continue
97             try:
98                 # get gid from the registry
99                 interface_info =  self.interfaces[new_hrn]
100                 interface = self[new_hrn]
101                 trusted_gids = interface.get_trusted_certs()
102                 if trusted_gids:
103                     # the gid we want shoudl be the first one in the list, 
104                     # but lets make sure
105                     for trusted_gid in trusted_gids:
106                         # default message
107                         message = "interface: %s\t" % (self.api.interface)
108                         message += "unable to install trusted gid for %s" % \
109                                    (new_hrn) 
110                         gid = GID(string=trusted_gids[0])
111                         peer_gids.append(gid) 
112                         if gid.get_hrn() == new_hrn:
113                             gid_filename = os.path.join(trusted_certs_dir, '%s.gid' % new_hrn)
114                             gid.save_to_file(gid_filename, save_parents=True)
115                             message = "interface: %s\tinstalled trusted gid for %s" % \
116                                 (self.api.interface, new_hrn)
117                         # log the message
118                         self.api.logger.info(message)
119             except:
120                 message = "interface: %s\tunable to install trusted gid for %s" % \
121                             (self.api.interface, new_hrn) 
122                 self.api.logger.info(message)
123                 traceback.print_exc()
124         
125         # reload the trusted certs list
126         self.api.auth.load_trusted_certs()
127         return peer_gids
128
129     def update_db_records(self, type, gids):
130         """
131         Make sure there is a record in the local db for allowed registries
132         defined in the config file (registries.xml). Removes old records from
133         the db.         
134         """
135         if not gids: 
136             return
137         # get hrns we expect to find
138         # ignore records for local interfaces
139         ignore_interfaces = [self.api.config.SFA_INTERFACE_HRN]
140         hrns_expected = [gid.get_hrn() for gid in gids \
141                          if gid.get_hrn() not in ignore_interfaces]
142
143         # get hrns that actually exist in the db
144         table = SfaTable()
145         records = table.find({'type': type})
146         hrns_found = [record['hrn'] for record in records]
147        
148         # remove old records
149         for record in records:
150             if record['hrn'] not in hrns_expected:
151                 table.remove(record)
152
153         # add new records
154         for gid in gids:
155             hrn = gid.get_hrn()
156             if hrn not in hrns_found:
157                 record = {
158                     'hrn': hrn,
159                     'type': type,
160                     'pointer': -1, 
161                     'authority': get_authority(hrn),
162                     'gid': gid.save_to_string(save_parents=True),
163                 }
164                 record = SfaRecord(dict=record)
165                 table.insert(record)
166                         
167     def get_connections(self):
168         """
169         read connection details for the trusted peer registries from file return 
170         a dictionary of connections keyed on interface hrn. 
171         """
172         connections = {}
173         required_fields = self.default_fields.keys()
174         for interface in self.interfaces.values():
175             # make sure the required fields are present and not null
176             if not all([interface.get(key) for key in required_fields]):
177                 continue
178  
179             hrn, address, port = interface['hrn'], interface['addr'], interface['port']
180             url = 'http://%(address)s:%(port)s' % locals()
181             # check which client we should use
182             # sfa.util.xmlrpcprotocol is default
183             client_type = 'xmlrpcprotocol'
184             if interface.has_key('client') and \
185                interface['client'] in ['geniclientlight'] and \
186                GeniClientLight:
187                 client_type = 'geniclientlight'
188                 connections[hrn] = GeniClientLight(url, self.api.key_file, self.api.cert_file) 
189             else:
190                 connections[hrn] = xmlrpcprotocol.get_server(url, self.api.key_file, self.api.cert_file)
191
192         return connections