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