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