072f3b6f6c47e029a966c0ac660bf50a5c6b5567
[sfa.git] / sfa / server / sfa_component_setup.py
1 #!/usr/bin/python
2 import sys
3 import os
4 import tempfile
5 from optparse import OptionParser
6
7 from sfa.util.faults import ConnectionKeyGIDMismatch
8 from sfa.util.config import Config
9 import sfa.util.xmlrpcprotocol as xmlrpcprotocol
10 from sfa.util.plxrn import hrn_to_pl_slicename, slicename_to_hrn
11
12 from sfa.trust.certificate import Keypair, Certificate
13 from sfa.trust.credential import Credential
14 from sfa.trust.gid import GID
15 from sfa.trust.hierarchy import Hierarchy
16
17 KEYDIR = "/var/lib/sfa/"
18 CONFDIR = "/etc/sfa/"
19
20 def handle_gid_mismatch_exception(f):
21     def wrapper(*args, **kwds):
22         try: return f(*args, **kwds)
23         except ConnectionKeyGIDMismatch:
24             # clean regen server keypair and try again
25             print "cleaning keys and trying again"
26             clean_key_cred()
27             return f(args, kwds)
28
29     return wrapper
30
31 def get_server(url=None, port=None, keyfile=None, certfile=None,verbose=False):
32     """
33     returns an xmlrpc connection to the service a the specified 
34     address
35     """
36     if url:
37         url_parts = url.split(":")
38         if len(url_parts) >1:
39             pass
40         else:
41             url = "http://%(url)s:%(port)s" % locals()
42     else:
43         # connect to registry by default
44         config = Config()
45         addr, port = config.SFA_REGISTRY_HOST, config.SFA_REGISTRY_PORT
46         url = "http://%(addr)s:%(port)s" % locals()
47
48     if verbose:
49         print "Contacting registry at: %(url)s" % locals()
50
51     server = xmlrpcprotocol.get_server(url, keyfile, certfile)
52     return server    
53     
54
55 def create_default_dirs():
56     config = Config()
57     hierarchy = Hierarchy()
58     config_dir = config.config_path
59     trusted_certs_dir = config.get_trustedroots_dir()
60     authorities_dir = hierarchy.basedir
61     all_dirs = [config_dir, trusted_certs_dir, authorities_dir]
62     for dir in all_dirs:
63         if not os.path.exists(dir):
64             os.makedirs(dir)
65
66 def has_node_key():
67     key_file = KEYDIR + os.sep + 'server.key'
68     return os.path.exists(key_file) 
69
70 def clean_key_cred():
71     """
72     remove the existing keypair and cred  and generate new ones
73     """
74     files = ["server.key", "server.cert", "node.cred"]
75     for f in files:
76         filepath = KEYDIR + os.sep + f
77         if os.path.isfile(filepath):
78             os.unlink(f)
79    
80     # install the new key pair
81     # get_credential will take care of generating the new keypair
82     # and credential 
83     get_credential()
84     
85              
86 def get_node_key(registry=None, verbose=False):
87     # this call requires no authentication, 
88     # so we can generate a random keypair here
89     subject="component"
90     (kfd, keyfile) = tempfile.mkstemp()
91     (cfd, certfile) = tempfile.mkstemp()
92     key = Keypair(create=True)
93     key.save_to_file(keyfile)
94     cert = Certificate(subject=subject)
95     cert.set_issuer(key=key, subject=subject)
96     cert.set_pubkey(key)
97     cert.sign()
98     cert.save_to_file(certfile)
99     
100     registry = get_server(url = registry, keyfile=keyfile, certfile=certfile)    
101     registry.get_key()
102
103 def create_server_keypair(keyfile=None, certfile=None, hrn="component", verbose=False):
104     """
105     create the server key/cert pair in the right place
106     """
107     key = Keypair(filename=keyfile)
108     key.save_to_file(keyfile)
109     cert = Certificate(subject=hrn)
110     cert.set_issuer(key=key, subject=hrn)
111     cert.set_pubkey(key)
112     cert.sign()
113     cert.save_to_file(certfile, save_parents=True)       
114
115 @handle_gid_mismatch_exception
116 def get_credential(registry=None, force=False, verbose=False):
117     config = Config()
118     hierarchy = Hierarchy()
119     key_dir= hierarchy.basedir
120     data_dir = config.data_path
121     config_dir = config.config_path
122     credfile = data_dir + os.sep + 'node.cred'
123     # check for existing credential
124     if not force and os.path.exists(credfile):
125         if verbose:
126             print "Loading Credential from %(credfile)s " % locals()  
127         cred = Credential(filename=credfile).save_to_string(save_parents=True)
128     else:
129         if verbose:
130             print "Getting credential from registry" 
131         # make sure node private key exists
132         node_pkey_file = config_dir + os.sep + "node.key"
133         node_gid_file = config_dir + os.sep + "node.gid"
134         if not os.path.exists(node_pkey_file) or \
135            not os.path.exists(node_gid_file):
136             get_node_key(registry=registry, verbose=verbose)
137         
138         gid = GID(filename=node_gid_file)
139         hrn = gid.get_hrn()
140         # create server key and certificate
141         keyfile =data_dir + os.sep + "server.key"
142         certfile = data_dir + os.sep + "server.cert"
143         key = Keypair(filename=node_pkey_file)
144         key.save_to_file(keyfile)
145         create_server_keypair(keyfile, certfile, hrn, verbose)
146
147         # get credential from registry 
148         registry = get_server(url=registry, keyfile=keyfile, certfile=certfile)
149         cert = Certificate(filename=certfile)
150         cert_str = cert.save_to_string(save_parents=True)
151         cred = registry.GetSelfCredential(cert_str, 'node', hrn)
152         Credential(string=cred).save_to_file(credfile, save_parents=True)
153     
154     return cred
155
156 @handle_gid_mismatch_exception
157 def get_trusted_certs(registry=None, verbose=False):
158     """
159     refresh our list of trusted certs.
160     """
161     # define useful variables
162     config = Config()
163     data_dir = config.SFA_DATA_DIR
164     config_dir = config.SFA_CONFIG_DIR
165     trusted_certs_dir = config.get_trustedroots_dir()
166     keyfile = data_dir + os.sep + "server.key"
167     certfile = data_dir + os.sep + "server.cert"
168     node_gid_file = config_dir + os.sep + "node.gid"
169     node_gid = GID(filename=node_gid_file)
170     hrn = node_gid.get_hrn()
171     # get credential
172     cred = get_credential(registry=registry, verbose=verbose)
173     # make sure server key cert pair exists
174     create_server_keypair(keyfile=keyfile, certfile=certfile, hrn=hrn, verbose=verbose)
175     registry = get_server(url=registry, keyfile=keyfile, certfile=certfile)
176     # get the trusted certs and save them in the right place
177     if verbose:
178         print "Getting trusted certs from registry"
179     trusted_certs = registry.get_trusted_certs(cred)
180     trusted_gid_names = [] 
181     for gid_str in trusted_certs:
182         gid = GID(string=gid_str)
183         gid.decode()
184         relative_filename = gid.get_hrn() + ".gid"
185         trusted_gid_names.append(relative_filename)
186         gid_filename = trusted_certs_dir + os.sep + relative_filename
187         if verbose:
188             print "Writing GID for %s as %s" % (gid.get_hrn(), gid_filename) 
189         gid.save_to_file(gid_filename, save_parents=True)
190
191     # remove old certs
192     all_gids_names = os.listdir(trusted_certs_dir)
193     for gid_name in all_gids_names:
194         if gid_name not in trusted_gid_names:
195             if verbose:
196                 print "Removing old gid ", gid_name
197             os.unlink(trusted_certs_dir + os.sep + gid_name)                     
198
199 @handle_gid_mismatch_exception
200 def get_gids(registry=None, verbose=False):
201     """
202     Get the gid for all instantiated slices on this node and store it
203     in /etc/sfa/slice.gid in the slice's filesystem
204     """
205     # define useful variables
206     config = Config()
207     data_dir = config.data_path
208     config_dir = config.SFA_CONFIG_DIR
209     trusted_certs_dir = config.get_trustedroots_dir()
210     keyfile = data_dir + os.sep + "server.key"
211     certfile = data_dir + os.sep + "server.cert"
212     node_gid_file = config_dir + os.sep + "node.gid"
213     node_gid = GID(filename=node_gid_file)
214     hrn = node_gid.get_hrn()
215     interface_hrn = config.SFA_INTERFACE_HRN
216     # get credential
217     cred = get_credential(registry=registry, verbose=verbose)
218     # make sure server key cert pair exists
219     create_server_keypair(keyfile=keyfile, certfile=certfile, hrn=hrn, verbose=verbose)
220     registry = get_server(url=registry, keyfile=keyfile, certfile=certfile)
221             
222     if verbose:
223         print "Getting current slices on this node"
224     # get a list of slices on this node
225     # make sure you run with SFA_GENERIC_FLAVOUR=plcm 
226     from sfa.generic import Generic
227     generic=Generic.the_flavour()
228     api = generic.make_api(interface='component')
229     xids_tuple = api.driver.nodemanager.GetXIDs()
230     slices = eval(xids_tuple[1])
231     slicenames = slices.keys()
232
233     # generate a list of slices that dont have gids installed
234     slices_without_gids = []
235     for slicename in slicenames:
236         if not os.path.isfile("/vservers/%s/etc/slice.gid" % slicename) \
237         or not os.path.isfile("/vservers/%s/etc/node.gid" % slicename):
238             slices_without_gids.append(slicename) 
239     
240     # convert slicenames to hrns
241     hrns = [slicename_to_hrn(interface_hrn, slicename) \
242             for slicename in slices_without_gids]
243     
244     # exit if there are no gids to install
245     if not hrns:
246         return
247         
248     if verbose:
249         print "Getting gids for slices on this node from registry"  
250     # get the gids
251     # and save them in the right palce
252     records = registry.GetGids(hrns, cred)
253     for record in records:
254         # if this isnt a slice record skip it
255         if not record['type'] == 'slice':
256             continue
257         slicename = hrn_to_pl_slicename(record['hrn'])
258         # if this slice isnt really instatiated skip it
259         if not os.path.exists("/vservers/%(slicename)s" % locals()):
260             continue
261        
262         # save the slice gid in /etc/sfa/ in the vservers filesystem
263         vserver_path = "/vservers/%(slicename)s" % locals()
264         gid = record['gid']
265         slice_gid_filename = os.sep.join([vserver_path, "etc", "slice.gid"])
266         if verbose:
267             print "Saving GID for %(slicename)s as %(slice_gid_filename)s" % locals()
268         GID(string=gid).save_to_file(slice_gid_filename, save_parents=True)
269         # save the node gid in /etc/sfa
270         node_gid_filename = os.sep.join([vserver_path, "etc", "node.gid"])
271         if verbose:
272             print "Saving node GID for %(slicename)s as %(node_gid_filename)s" % locals()
273         node_gid.save_to_file(node_gid_filename, save_parents=True) 
274                 
275
276 def dispatch(options, args):
277
278     create_default_dirs()
279     if options.key:
280         if options.verbose:
281             print "Getting the component's pkey"
282         get_node_key(registry=options.registry, verbose=options.verbose)
283     if options.certs:
284         if options.verbose:
285             print "Getting the component's trusted certs"
286         get_trusted_certs(verbose=options.verbose)
287     if options.gids:        
288         if options.verbose:
289             print "Geting the component's GIDs"
290         get_gids(verbose=options.verbose)
291
292 def main():
293     args = sys.argv
294     prog_name = args[0]
295     parser = OptionParser(usage="%(prog_name)s [options]" % locals())
296     parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
297                       default=False, help="Be verbose") 
298     parser.add_option("-r", "--registry", dest="registry", default=None,
299                       help="Url of registry to contact")  
300     parser.add_option("-k", "--key", dest="key", action="store_true", 
301                      default=False,  
302                      help="Get the node's pkey from the registry")
303     parser.add_option("-c", "--certs", dest="certs", action="store_true",
304                       default=False,
305                       help="Get the trusted certs from the registry")
306     parser.add_option("-g", "--gids", dest="gids", action="store_true",       
307                       default=False,
308                       help="Get gids for all the slices on the component")
309
310     (options, args) = parser.parse_args()
311
312     dispatch(options, args)
313
314 if __name__ == '__main__':
315     main()