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