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