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