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