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