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