a3b06ef67655f74516bda160db33fdd93df28dc8
[sfa.git] / sfa / server / interface.py
1 import traceback
2 import os.path
3
4 from sfa.util.sfalogging import sfa_logger
5 from sfa.util.faults import *
6 from sfa.util.storage import XmlStorage
7 from sfa.util.xrn import get_authority, hrn_to_urn
8 from sfa.util.record import SfaRecord
9 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
10 import sfa.util.soapprotocol as soapprotocol
11 from sfa.trust.gid import GID
12
13 # GeniLight client support is optional
14 try:
15     from egeni.geniLight_client import *
16 except ImportError:
17     GeniClientLight = None            
18
19
20 ##
21 # In is a dictionary of registry connections keyed on the registry
22 # hrn
23
24 class Interfaces(dict):
25     """
26     Interfaces is a base class for managing information on the
27     peers we are federated with. It is responsible for the following:
28
29     1) Makes sure a record exist in the local registry for the each 
30        fedeated peer   
31     2) Attempts to fetch and install trusted gids   
32     3) Provides connections (xmlrpc or soap) to federated peers
33     """
34
35     # fields that must be specified in the config file
36     default_fields = {
37         'hrn': '',
38         'addr': '', 
39         'port': '', 
40     }
41
42     # defined by the class 
43     default_dict = {}
44
45     types = ['authority']
46
47     def __init__(self, api, conf_file, type='authority'):
48         if type not in self.types:
49             raise SfaInfaildArgument('Invalid type %s: must be in %s' % (type, self.types))    
50         dict.__init__(self, {})
51         self.api = api
52         self.type = type  
53         # load config file
54         self.interface_info = XmlStorage(conf_file, self.default_dict)
55         self.interface_info.load()
56         interfaces = self.interface_info.values()[0].values()[0]
57         if not isinstance(interfaces, list):
58             interfaces = [self.interfaces]
59         # set the url and urn 
60         for interface in interfaces:
61             # port is appended onto the domain, before the path. Should look like:
62             # http://domain:port/path
63             hrn, address, port = interface['hrn'], interface['addr'], interface['port']
64             address_parts = address.split('/')
65             address_parts[0] = address_parts[0] + ":" + str(port)
66             url =  "http://%s" %  "/".join(address_parts)
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.log_exc(message)
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 ComponentAPI 
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             url = interface['url']
194 #            sfa_logger().debug("Interfaces.get_connections - looping on neighbour %s"%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