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