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