bootstraps credentials
[sfa.git] / cmdline / sfi.py
1 #! /usr/bin/env python
2 from __future__ import with_statement
3
4 # sfi -- slice-based facility interface
5
6 import sys
7 import os, os.path
8 from cert import Keypair, Certificate, Credential
9 from optparse import OptionParser
10 from util.geniclient import GeniClient
11
12 sfi_dir = os.path.expanduser("~/.sfi/")
13 sm_chan = None
14 reg_chan = None
15 user = None
16 authority = None
17 verbose = False
18
19 #
20 # Establish Connection to SliceMgr and Registry Servers
21 #
22 def set_servers(options):
23    global sm_chan
24    global reg_chan
25    global user
26    global authority
27
28    # Set SliceMgr URL
29    if (options.sm is not None):
30       sm_url = options.sm
31    elif ("SFI_SM" in os.environ):
32       sm_url = os.environ["SFI_SM"]
33    else:
34       print "No Known Slice Manager"
35       sys.exit(1)
36
37    # Set Registry URL
38    if (options.registry is not None):
39       reg_url = options.registry
40    elif ("SFI_REGISTRY" in os.environ):
41       reg_url = os.environ["SFI_REGISTRY"]
42    else:
43       print "No Known Registry Server"
44       sys.exit(1)
45
46    if options.verbose :
47       print "Contacting Slice Manager at:", sm_url
48       print "Contacting Registry at:", registry_url
49
50    # Set user HRN
51    if (options.user is not None):
52       user = options.user
53    elif ("SFI_USER" in os.environ):
54       user = os.environ["SFI_USER"]
55    else:
56       print "No Known User Name"
57       sys.exit(1)
58
59    # Set authority HRN
60    if (options.auth is not None):
61       authority = options.auth
62    elif ("SFI_AUTH" in os.environ):
63       authority = os.environ["SFI_AUTH"]
64    else:
65       authority = None
66
67    # Get key and certificate   
68    key_file = get_key_file()
69    cert_file = get_cert_file(key_file)
70
71    # Establish connection to server(s)
72    # SliceMgr and Registry may be available on the same server
73    if (sm_url == registry_url):
74       sm_chan = GeniClient(sm_url, key_file, cert_file)
75       reg_chan = sm_chan
76    else:
77       sm_chan = GeniClient(sm_url, key_file, cert_file)
78       reg_chan = GeniClient(registry_url, key_file, cert_file)
79    return
80
81 #
82 # Get various credential and spec files
83 #
84 # Establishes limiting conventions
85 #   - conflates MAs and SAs
86 #   - assumes last token in slice name is unique
87 #
88 # Bootstraps credentials
89 #   - bootstrap user credential from self-signed certificate
90 #   - bootstrap authority credential from user credential
91 #   - bootstrap slice credential from user credential
92 #
93
94 def get_leaf(name):
95    parts = name.split(".")
96    return parts[-1]
97
98 def get_key_file():
99    file = os.path.join(sfi_dir, get_leaf(user) + ".pkey")
100    if (os.path.isfile(file)):
101       return file
102    else:
103       print "Key file", file, "does not exist"
104       sys.exit(-1)
105    return
106
107 def get_cert_file(key_file):
108    global verbose
109
110    file = os.path.join(sfi_dir, get_leaf(user) + ".cert")
111    if (os.path.isfile(file)):
112       return file
113    else:
114       k = Keypair(filename = key_file)
115       cert = Certificate(subject=user)
116       cert.set_pubkey(k)
117       cert.set_issuer(k, user)
118       cert.sign()
119       if verbose :
120          print "Writing self-signed certificate to", file
121       cert.save_to_file(file)
122       return file
123
124 def get_user_cred():
125    global user
126
127    file = os.path.join(sfi_dir, get_leaf(user) + ".cred")
128    if (os.path.isfile(file)):
129       user_cred = Credential(filename=file)
130       return user_cred
131    else:
132       # bootstrap user credential
133       user_cred = get_credential(None, "user", user)
134       if user_cred:
135          user_cred.save_to_file(file, save_parents=True)
136          if verbose:
137             print "Writing user credential to", file
138          return user_cred
139       else:
140          print "Failed to get user credential"
141          sys.exit(-1)
142
143 def get_auth_cred():
144    global authority
145
146    file = os.path.join(sfi_dir, "authority.cred")
147    if (os.path.isfile(file)):
148       auth_cred = Credential(filename=file)
149       return auth_cred
150    else:
151       # bootstrap authority credential from user credential
152       user_cred = get_user_cred()
153       auth_cred = get_credential(user_cred, "sa", authority)
154       if auth_cred:
155          auth_cred.save_to_file(file, save_parents=True)
156          if verbose:
157             print "Writing authority credential to", file
158          return auth_cred
159       else:
160          print "Failed to get authority credential"
161          sys.exit(-1)
162
163 def get_slice_cred(name):
164    file = os.path.join(sfi_dir, "slice_" + get_leaf(name) + ".cred")
165    if (os.path.isfile(file)):
166       slice_cred = Credential(filename=file)
167       return slice_cred
168    else:
169       # bootstrap slice credential from user credential
170       user_cred = get_user_cred()
171       slice_cred = get_credential(user_cred, "slice", name)
172       if slice_cred:
173          slice_cred.save_to_file(file, save_parents=True)
174          if verbose:
175             print "Writing slice credential to", file
176          return slice_cred
177       else:
178          print "Failed to get slice credential"
179          sys.exit(-1)
180
181 def get_rspec_file(rspec):
182    if (os.path.isabs(rspec)):
183       file = rspec
184    else:
185       file = os.path.join(sfi_dir, rspec)
186    if (os.path.isfile(file)):
187       return file
188    else:
189       print "No such rspec file"
190       sys.exit(1)
191
192 def get_record_file(record):
193    if (os.path.isabs(record)):
194       file = record
195    else:
196       file = os.path.join(sfi_dir, record)
197    if (os.path.isfile(file)):
198       return file
199    else:
200       print "No such registry record file"
201       sys.exit(1)
202
203 #
204 # Generate sub-command parser
205 #
206 def create_cmd_parser(command):
207    cmdargs = {"list": "name",
208               "show": "name",
209               "remove": "name",
210               "add": "name record",
211               "update": "name record",
212               "nodes": "[name]",
213               "slices": "",
214               "resources": "name",
215               "create": "name rspec",
216               "delete": "name",
217               "reset": "name",
218               "start": "name",
219               "stop": "name"
220              }
221    if command not in cmdargs:
222       print "Invalid command\n"
223       print "Commands:list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset"
224       sys.exit(2)
225
226    parser = OptionParser(usage="sfi [sfi_options] %s [options] %s" \
227       % (command, cmdargs[command]))
228    if command in ("nodes", "resources"):
229       parser.add_option("-f", "--format", dest="format",type="choice",
230            help="output format (dns|ip|hrn|rspec)",default="rspec",
231            choices=("dns","ip","hrn","rspec"))
232    elif command in ("list", "show", "remove"):
233       parser.add_option("-t", "--type", dest="type",type="choice",
234            help="type filter (user|slice|sa|ma|node|aggregate)", 
235            choices=("user","slice","sa","ma","node","aggregate", "all"),
236            default="all")
237    return parser
238
239 #
240 # Main: parse arguments and dispatch to command
241 #
242 def main():
243    global sm_chan
244    global reg_chan
245    global verbose
246
247    # Generate command line parser
248    parser = OptionParser(usage="sfi [options] command [command_options] [command_args]",
249         description="Commands: list,show,remove,add,update,nodes,slices,resources,create,delete,start,stop,reset")
250    parser.add_option("-r", "--registry", dest="registry",
251         help="root registry", metavar="URL", default=None)
252    parser.add_option("-s", "--slicemgr", dest="sm",
253         help="slice manager", metavar="URL", default=None)
254    parser.add_option("-d", "--dir", dest="dir",
255         help="working directory", metavar="PATH", default = sfi_dir)
256    parser.add_option("-u", "--user", dest="user",
257         help="user name", metavar="USER_HRN", default=None)
258    parser.add_option("-a", "--auth", dest="auth",
259         help="authority name", metavar="AUTH_HRN", default=None)
260    parser.add_option("-v", "--verbose",
261         action="store_true", dest="verbose", default=False,
262         help="verbose mode")
263    parser.disable_interspersed_args()
264    (options, args) = parser.parse_args()
265    command = args[0]
266    (cmd_opts, cmd_args) = create_cmd_parser(command).parse_args(args[1:])
267    verbose = options.verbose
268    if verbose :
269       print options.registry, options.sm, options.dir, options.verbose,\
270          options.user, options.auth
271       print command
272       if command in ("nodes", "resources"):
273          print cmd_opts.format
274       elif command in ("list","show","remove"):
275          print cmd_opts.type
276       print cmd_args 
277
278    set_servers(options)
279
280    # Dispatch to selected command
281    try:
282       globals()[command](cmd_opts, cmd_args)
283    except KeyError:
284       print "Command not found:", command
285       sys.exit(1)
286    return
287
288 #
289 # Following functions implement the commands
290 #
291 # Registry-related commands
292 #
293
294 # list entires in named authority registry
295 def list(opts, args):
296    global reg_chan
297    user_cred = get_user_cred()
298    result = reg_chan.list(user_cred, args[0])
299    display_record(opts.type, results)
300    return
301
302 # show named registry record
303 def show(opts, args):
304    global reg_chan
305    user_cred = get_user_cred() 
306    result = reg_chan.resolve(user_cred, args[0])
307    display_record(opts.type, results)
308    return
309
310 # removed named registry record
311 #   - have to first retrieve the record to be removed
312 def remove(opts, args):
313    global reg_chan
314    auth_cred = get_auth_cred() 
315    results = reg_chan.resolve(auth_cred, args[0])
316    record = filter_record(opts.type, results)
317    return reg_chan.remove(auth_cred, record)
318
319 # add named registry record
320 def add(opts, args):
321    global reg_chan
322    auth_cred = get_auth_cred() 
323    rec_file = get_record_file(args[1])
324    with open(rec_file) as f:
325       record = f.read()
326    return reg_chan.register(auth_cred, record)
327
328 # update named registry entry
329 def update(opts, args):
330    global reg_chan
331    user_cred = get_user_cred() 
332    rec_file = get_record_file(args[1])
333    with open(rec_file) as f:
334       record = f.read()
335    return reg_chan.update(user_cred, record)
336
337 #
338 # Slice-related commands
339 #
340
341 # list available nodes
342 def nodes(opts, args):
343    global sm_chan
344    user_cred = get_user_cred() 
345    if (len(args) == 0):
346       context = None
347    else:
348       context = args[0]
349    result = sm_chan.list_nodes(user_cred, context)
350    display_rspec(opts.format, result)
351    return
352
353 # list instantiated slices
354 def slices(opts, args):
355    global sm_chan
356    user_cred = get_user_cred() 
357    result = sm_chan.list_slices(user_cred)
358    display_rspec(opts.format, results)
359    return
360
361 # show rspec for named slice
362 def resources(opts, args):
363    global sm_chan
364    slice_cred = get_slice_cred(args[0]) 
365    print "resources:", opts.format, args[0], sm_chan
366    result = sm_chan.get_resources(slice_cred, args[0])
367    display_rspec(opts.format, result)
368    return
369
370 # created named slice with given rspec
371 def create(opts, args):
372    global sm_chan
373    slice_cred = get_slice_cred(args[0]) 
374    rspec_file = get_rspec_file(args[1])
375    with open(rspec_file) as f:
376       rspec = f.read()
377    return sm_chan.instantiate(slice_cred, rspec)
378
379 # delete named slice
380 def delete(opts, args):
381    global sm_chan
382    slice_cred = get_slice_cred(args[0]) 
383    return sm_chan.delete_slice(slice_cred)
384
385 # start named slice
386 def start(opts, args):
387    global sm_chan
388    slice_cred = get_slice_cred(args[0]) 
389    return sm_chan.start_slice(slice_cred)
390
391 # stop named slice
392 def stop(opts, args):
393    global sm_chan
394    slice_cred = get_slice_cred(args[0]) 
395    return sm_chan.stop_slice(slice_cred)
396
397 # reset named slice
398 def reset(opts, args):
399    global sm_chan
400    slice_cred = get_slice_cred(args[0]) 
401    return sm_chan.reset_slice(slice_cred)
402
403 #
404 #
405 # Display and Filter RSpecs and Records
406 #
407 #
408
409 def display_rspec(format, rspec):
410    print "display rspec"
411    return
412
413 def display_record(type, record):
414    rec = filter_record(type, record)
415    print "display record"
416    return
417
418 def filter_record(type, record):
419    print "filter record"
420    return
421
422
423 if __name__=="__main__":
424    main()