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