remove debugging output
[sfa.git] / sfa / clientbin / sfaadmin.py
1 #!/usr/bin/python
2 import os
3 import sys
4 import copy
5 from pprint import pformat 
6 from sfa.generic import Generic
7 from optparse import OptionParser
8 from pprint import PrettyPrinter
9 from sfa.util.xrn import Xrn
10 from sfa.storage.record import Record 
11 from sfa.client.sfi import save_records_to_file
12 from sfa.trust.hierarchy import Hierarchy
13 from sfa.trust.gid import GID
14
15 pprinter = PrettyPrinter(indent=4)
16
17 def optparse_listvalue_callback(option, opt, value, parser):
18     setattr(parser.values, option.dest, value.split(','))
19
20 def args(*args, **kwargs):
21     def _decorator(func):
22         func.__dict__.setdefault('options', []).insert(0, (args, kwargs))
23         return func
24     return _decorator
25
26 class Commands(object):
27     def _get_commands(self):
28         available_methods = []
29         for attrib in dir(self):
30             if callable(getattr(self, attrib)) and not attrib.startswith('_'):
31                 available_methods.append(attrib)
32         return available_methods         
33
34
35 class RegistryCommands(Commands):
36     def __init__(self, *args, **kwds):
37         self.api= Generic.the_flavour().make_api(interface='registry')
38  
39     def version(self):
40         version = self.api.manager.GetVersion(self.api, {})
41         pprinter.pprint(version)
42
43     @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn') 
44     @args('-t', '--type', dest='type', metavar='<type>', help='object type', default=None) 
45     def list(self, xrn, type=None):
46         xrn = Xrn(xrn, type) 
47         records = self.api.manager.List(self.api, xrn.get_hrn())
48         for record in records:
49             if not type or record['type'] == type:
50                 print "%s (%s)" % (record['hrn'], record['type'])
51
52
53     @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn') 
54     @args('-t', '--type', dest='type', metavar='<type>', help='object type', default=None) 
55     @args('-o', '--outfile', dest='outfile', metavar='<outfile>', help='save record to file') 
56     @args('-f', '--format', dest='format', metavar='<display>', type='choice', 
57           choices=('text', 'xml', 'simple'), help='display record in different formats') 
58     def show(self, xrn, type=None, format=None, outfile=None):
59         records = self.api.manager.Resolve(self.api, xrn, type, True)
60         for record in records:
61             sfa_record = Record(dict=record)
62             sfa_record.dump(format) 
63         if outfile:
64             save_records_to_file(outfile, records)  
65
66
67     def _record_dict(self, xrn=None, type=None, url=None, key=None, \
68                      description=None, slices='', researchers=''):              
69         record_dict = {}
70         if xrn:
71             if type:
72                 xrn = Xrn(xrn, type)
73             else:
74                 xrn = Xrn(xrn)
75             record_dict['urn'] = xrn.get_urn()
76             record_dict['hrn'] = xrn.get_hrn()
77             record_dict['type'] = xrn.get_type()
78         if url:
79             record_dict['url'] = url
80         if key:
81             try:
82                 pubkey = open(key, 'r').read()
83             except IOError:
84                 pubkey = key
85             record_dict['keys'] = [pubkey]
86         if slices:
87             record_dict['slices'] = slices
88         if researchers:
89             record_dict['researchers'] = researchers
90         if description:
91             record_dict['description'] = description
92         return record_dict
93
94     @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn') 
95     @args('-t', '--type', dest='type', metavar='<type>', help='object type', default=None) 
96     @args('-u', '--url', dest='url', metavar='<url>', help='URL', default=None)
97     @args('-d', '--description', dest='description', metavar='<description>', 
98           help='Description', default=None)
99     @args('-k', '--key', dest='key', metavar='<key>', help='public key string or file', 
100           default=None)
101     @args('-s', '--slices', dest='slices', metavar='<slices>', help='slice xrns', 
102           default='', type="str", action='callback', callback=optparse_listvalue_callback)
103     @args('-r', '--researchers', dest='researchers', metavar='<researchers>', help='slice researchers', 
104           default='', type="str", action='callback', callback=optparse_listvalue_callback)
105     @args('-p', '--pis', dest='pis', metavar='<PIs>', 
106           help='Principal Investigators/Project Managers ', 
107           default='', type="str", action='callback', callback=optparse_listvalue_callback)
108     def register(self, xrn, type=None, url=None, description=None, key=None, slices='', 
109                  pis='', researchers=''):
110         record_dict = self._record_dict(xrn=xrn, type=type, url=url, key=key, 
111                                         slices=slices, researchers=researchers)
112         self.api.manager.Register(self.api, record_dict)         
113
114
115     @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn')
116     @args('-t', '--type', dest='type', metavar='<type>', help='object type', default=None)
117     @args('-u', '--url', dest='url', metavar='<url>', help='URL', default=None)
118     @args('-d', '--description', dest='description', metavar='<description>',
119           help='Description', default=None)
120     @args('-k', '--key', dest='key', metavar='<key>', help='public key string or file',
121           default=None)
122     @args('-s', '--slices', dest='slices', metavar='<slices>', help='slice xrns',
123           default='', type="str", action='callback', callback=optparse_listvalue_callback)
124     @args('-r', '--researchers', dest='researchers', metavar='<researchers>', help='slice researchers',
125           default='', type="str", action='callback', callback=optparse_listvalue_callback)
126     @args('-p', '--pis', dest='pis', metavar='<PIs>',
127           help='Principal Investigators/Project Managers ',
128           default='', type="str", action='callback', callback=optparse_listvalue_callback)
129     def update(self, xrn, type=None, url=None, description=None, key=None, slices='', 
130                pis='', researchers=''):
131         record_dict = self._record_dict(xrn=xrn, type=type, url=url, description=description, 
132                                         key=key, slices=slices, researchers=researchers)
133         self.api.manager.Update(self.api, record_dict)
134         
135     @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn') 
136     @args('-t', '--type', dest='type', metavar='<type>', help='object type', default=None) 
137     def remove(self, xrn, type=None):
138         xrn = Xrn(xrn, type)
139         self.api.manager.Remove(self.api, xrn)            
140
141
142     @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn') 
143     @args('-t', '--type', dest='type', metavar='<type>', help='object type', default=None) 
144     def credential(self, xrn, type=None):
145         cred = self.api.manager.GetCredential(self.api, xrn, type, self.api.hrn)
146         print cred
147    
148
149     def import_registry(self):
150         from sfa.importer import Importer
151         importer = Importer()
152         importer.run()
153     
154     @args('-a', '--all', dest='all', metavar='<all>', action='store_true', default=False,
155           help='Remove all registry records and all files in %s area' % Hierarchy().basedir)
156     @args('-c', '--certs', dest='certs', metavar='<certs>', action='store_true', default=False,
157           help='Remove all cached certs/gids found in %s' % Hierarchy().basedir )
158     @args('-0', '--no-reinit', dest='reinit', metavar='<reinit>', action='store_false', default=True,
159           help='Prevents new DB schema from being installed after cleanup')
160     def nuke(self, all=False, certs=False, reinit=True):
161         from sfa.storage.dbschema import DBSchema
162         from sfa.util.sfalogging import _SfaLogger
163         logger = _SfaLogger(logfile='/var/log/sfa_import.log', loggername='importlog')
164         logger.setLevelFromOptVerbose(self.api.config.SFA_API_LOGLEVEL)
165         logger.info("Purging SFA records from database")
166         dbschema=DBSchema()
167         dbschema.nuke()
168
169         # for convenience we re-create the schema here, so there's no need for an explicit
170         # service sfa restart
171         # however in some (upgrade) scenarios this might be wrong
172         if reinit:
173             logger.info("re-creating empty schema")
174             dbschema.init_or_upgrade()
175
176         # remove the server certificate and all gids found in /var/lib/sfa/authorities
177         if certs:
178             logger.info("Purging cached certificates")
179             for (dir, _, files) in os.walk('/var/lib/sfa/authorities'):
180                 for file in files:
181                     if file.endswith('.gid') or file == 'server.cert':
182                         path=dir+os.sep+file
183                         os.unlink(path)
184
185         # just remove all files that do not match 'server.key' or 'server.cert'
186         if all:
187             logger.info("Purging registry filesystem cache")
188             preserved_files = [ 'server.key', 'server.cert']
189             for (dir,_,files) in os.walk(Hierarchy().basedir):
190                 for file in files:
191                     if file in preserved_files: continue
192                     path=dir+os.sep+file
193                     os.unlink(path)
194         
195     
196 class CertCommands(Commands):
197     
198     def import_gid(self, xrn):
199         pass
200
201     @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn')
202     @args('-t', '--type', dest='type', metavar='<type>', help='object type', default=None)
203     @args('-o', '--outfile', dest='outfile', metavar='<outfile>', help='output file', default=None)
204     def export(self, xrn, type=None, outfile=None):
205         from sfa.storage.alchemy import dbsession
206         from sfa.storage.model import RegRecord
207         hrn = Xrn(xrn).get_hrn()
208         request=dbsession.query(RegRecord).filter_by(hrn=hrn)
209         if type: request = request.filter_by(type=type)
210         record=request.first()
211         if record:
212             gid = GID(string=record.gid)
213         else:
214             # check the authorities hierarchy
215             hierarchy = Hierarchy()
216             try:
217                 auth_info = hierarchy.get_auth_info(hrn)
218                 gid = auth_info.gid_object
219             except:
220                 print "Record: %s not found" % hrn
221                 sys.exit(1)
222         # save to file
223         if not outfile:
224             outfile = os.path.abspath('./%s.gid' % gid.get_hrn())
225         gid.save_to_file(outfile, save_parents=True)
226         
227     @args('-g', '--gidfile', dest='gid', metavar='<gid>', help='path of gid file to display') 
228     def display(self, gidfile):
229         gid_path = os.path.abspath(gidfile)
230         if not gid_path or not os.path.isfile(gid_path):
231             print "No such gid file: %s" % gidfile
232             sys.exit(1)
233         gid = GID(filename=gid_path)
234         gid.dump(dump_parents=True)
235     
236
237 class AggregateCommands(Commands):
238
239     def __init__(self, *args, **kwds):
240         self.api= Generic.the_flavour().make_api(interface='aggregate')
241    
242     def version(self):
243         version = self.api.manager.GetVersion(self.api, {})
244         pprinter.pprint(version)
245
246     def slices(self):
247         print self.api.manager.ListSlices(self.api, [], {})
248
249     @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn') 
250     def status(self, xrn):
251         urn = Xrn(xrn, 'slice').get_urn()
252         status = self.api.manager.SliverStatus(self.api, urn, [], {})
253         pprinter.pprint(status)
254  
255     @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn', default=None)
256     @args('-r', '--rspec-version', dest='rspec_version', metavar='<rspec_version>', 
257           default='GENI', help='version/format of the resulting rspec response')  
258     def resources(self, xrn=None, rspec_version='GENI'):
259         options = {'geni_rspec_version': rspec_version}
260         if xrn:
261             options['geni_slice_urn'] = xrn
262         resources = self.api.manager.ListResources(self.api, [], options)
263         print resources
264         
265     @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn', default=None)
266     @args('-r', '--rspec', dest='rspec', metavar='<rspec>', help='rspec file')  
267     @args('-u', '--user', dest='user', metavar='<user>', help='hrn/urn of slice user')  
268     @args('-k', '--key', dest='key', metavar='<key>', help="path to user's public key file")  
269     def create(self, xrn, rspec, user, key):
270         xrn = Xrn(xrn, 'slice')
271         slice_urn=xrn.get_urn()
272         rspec_string = open(rspec).read()
273         user_xrn = Xrn(user, 'user')
274         user_urn = user_xrn.get_urn()
275         user_key_string = open(key).read()
276         users = [{'urn': user_urn, 'keys': [user_key_string]}]
277         options={}
278         self.api.manager.CreateSliver(self, slice_urn, [], rspec_string, users, options) 
279
280     @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn', default=None)
281     def delete(self, xrn):
282         self.api.manager.DeleteSliver(self.api, xrn, [], {})
283  
284     @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn', default=None)
285     def start(self, xrn):
286         self.api.manager.start_slice(self.api, xrn, [])
287
288     @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn', default=None)
289     def stop(self, xrn):
290         self.api.manager.stop_slice(self.api, xrn, [])      
291
292     @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn', default=None)
293     def reset(self, xrn):
294         self.api.manager.reset_slice(self.api, xrn)
295
296
297     @args('-x', '--xrn', dest='xrn', metavar='<xrn>', help='object hrn/urn', default=None)
298     @args('-r', '--rspec', dest='rspec', metavar='<rspec>', help='request rspec', default=None)
299     def ticket(self, xrn, rspec):
300         pass
301
302
303
304 class SliceManagerCommands(AggregateCommands):
305     
306     def __init__(self, *args, **kwds):
307         self.api= Generic.the_flavour().make_api(interface='slicemgr')
308
309
310 CATEGORIES = {'cert': CertCommands,
311               'registry': RegistryCommands,
312               'aggregate': AggregateCommands,
313               'slicemgr': SliceManagerCommands}
314
315 def category_usage():
316     print "Available categories:"
317     for k in CATEGORIES:
318         print "\t%s" % k
319
320 def main():
321     argv = copy.deepcopy(sys.argv)
322     script_name = argv.pop(0)
323     # ensure category is specified    
324     if len(argv) < 1:
325         print script_name + " category action [<args>]"
326         category_usage()
327         sys.exit(2)
328
329     # ensure category is valid
330     category = argv.pop(0)
331     usage = "%%prog %s action <args> [options]" % (category)
332     parser = OptionParser(usage=usage)
333     command_class =  CATEGORIES.get(category, None)
334     if not command_class:
335         print "no such category %s " % category
336         category_usage()
337         sys.exit(2)  
338     
339     # ensure command is valid      
340     command_instance = command_class()
341     actions = command_instance._get_commands()
342     if len(argv) < 1:
343         action = '__call__'
344     else:
345         action = argv.pop(0)
346     
347     if hasattr(command_instance, action):
348         command = getattr(command_instance, action)
349     else:
350         print script_name + " category action [<args>]"
351         print "Available actions for %s category:" % category
352         for k in actions:
353             print "\t%s" % k
354         sys.exit(2)
355
356     # ensure options are valid
357     options = getattr(command, 'options', [])
358     usage = "%%prog %s %s <args> [options]" % (category, action)
359     parser = OptionParser(usage=usage)
360     for arg, kwd in options:
361         parser.add_option(*arg, **kwd)
362     (opts, cmd_args) = parser.parse_args(argv)
363     cmd_kwds = vars(opts)
364
365     # dont overrride meth
366     for k, v in cmd_kwds.items():
367         if v is None:
368             del cmd_kwds[k]
369
370     # execute commadn
371     try:
372         command(*cmd_args, **cmd_kwds)
373         sys.exit(0)
374     except TypeError:
375         print "Possible wrong number of arguments supplied"
376         print command.__doc__
377         parser.print_help()
378         #raise
379         raise
380     except Exception:
381         print "Command failed, please check log for more info"
382         raise
383
384
385 if __name__ == '__main__':
386     main()
387     
388      
389         
390