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