2424 import logging
2525 import os
2626 import pdb
27- import re
2827 import shlex
2928 import sys
29+ import types
3030
3131 from urllib2 import HTTPError , URLError
3232 from httplib import BadStatusLine
3333
34- from config import __version__ , config_file
35- from config import precached_verbs , read_config , write_config
34+ from config import __version__ , cache_file
35+ from config import read_config , write_config
36+
3637 from printer import monkeyprint
3738 from requester import monkeyrequest
39+ from cachemaker import loadcache , savecache , monkeycache
40+ from cachemaker import splitverbsubject
3841
3942 from prettytable import PrettyTable
40- from marvin .cloudstackConnection import cloudConnection
41- from marvin .cloudstackException import cloudstackAPIException
42- from marvin .cloudstackAPI import *
43- from marvin import cloudstackAPI
4443except ImportError , e :
4544 print "Import error in %s : %s" % (__name__ , e )
4645 import sys
4746 sys .exit ()
4847
48+ try :
49+ from precache import apicache
50+ except ImportError :
51+ apicache = {}
52+
4953# Fix autocompletion issue, can be put in .pythonstartup
5054try :
5155 import readline
6064
6165log_fmt = '%(asctime)s - %(filename)s:%(lineno)s - [%(levelname)s] %(message)s'
6266logger = logging .getLogger (__name__ )
63- completions = cloudstackAPI .__all__
6467
6568
6669class CloudMonkeyShell (cmd .Cmd , object ):
6770 intro = ("☁ Apache CloudStack 🐵 cloudmonkey " + __version__ +
6871 ". Type help or ? to list commands.\n " )
6972 ruler = "="
70- apicache = {}
71- # datastructure {'verb': {cmd': ['api', [params], doc, required=[]]}}
72- cache_verbs = precached_verbs
73+ cache_file = cache_file
74+ ## datastructure {'verb': {cmd': ['api', [params], doc, required=[]]}}
75+ # cache_verbs = apicache
7376 config_options = []
7477
75- def __init__ (self , pname , verbs ):
78+ def __init__ (self , pname ):
7679 self .program_name = pname
77- self .verbs = verbs
78-
7980 self .config_options = read_config (self .get_attr , self .set_attr )
81+ self .loadcache ()
8082 self .prompt = self .prompt .strip () + " " # Cosmetic fix for prompt
8183
8284 logging .basicConfig (filename = self .log_file ,
@@ -111,8 +113,27 @@ def cmdloop(self, intro=None):
111113 except KeyboardInterrupt :
112114 print ("^C" )
113115
116+ def loadcache (self ):
117+ if os .path .exists (self .cache_file ):
118+ self .apicache = loadcache (self .cache_file )
119+ else :
120+ self .apicache = apicache
121+ self .verbs = apicache ['verbs' ]
122+
114123 def monkeyprint (self , * args ):
115- monkeyprint ((self .color == 'true' ), * args )
124+ output = ""
125+ try :
126+ for arg in args :
127+ if isinstance (type (arg ), types .NoneType ):
128+ continue
129+ output += str (arg )
130+ except Exception , e :
131+ print e
132+
133+ if self .color == 'true' :
134+ monkeyprint (output )
135+ else :
136+ print output
116137
117138 def print_result (self , result , result_filter = None ):
118139 if result is None or len (result ) == 0 :
@@ -186,6 +207,9 @@ def default(self, args):
186207 if self .pipe_runner (args ):
187208 return
188209
210+ apiname = args .partition (' ' )[0 ]
211+ verb , subject = splitverbsubject (apiname )
212+
189213 lexp = shlex .shlex (args .strip ())
190214 lexp .whitespace = " "
191215 lexp .whitespace_split = True
@@ -196,7 +220,6 @@ def default(self, args):
196220 if next_val is None :
197221 break
198222 args .append (next_val )
199- api_name = args [0 ]
200223
201224 args_dict = dict (map (lambda x : [x .partition ("=" )[0 ],
202225 x .partition ("=" )[2 ]],
@@ -207,22 +230,15 @@ def default(self, args):
207230 map (lambda x : x .strip (),
208231 args_dict .pop ('filter' ).split (',' )))
209232
210- for attribute in args_dict .keys ():
211- setattr (api_cmd , attribute , args_dict [attribute ])
212-
213- #command = api_cmd()
214- #missing_args = filter(lambda x: x not in args_dict.keys(),
215- # command.required)
216-
217- #if len(missing_args) > 0:
218- # self.monkeyprint("Missing arguments: ", ' '.join(missing_args))
219- # return
233+ missing_args = filter (lambda x : x not in args_dict .keys (),
234+ self .apicache [verb ][subject ]['requiredparams' ])
220235
221- isAsync = False
222- #if "isAsync" in dir(command):
223- # isAsync = (command.isAsync == "true")
236+ if len ( missing_args ) > 0 :
237+ self . monkeyprint ( "Missing arguments: " , ' ' . join ( missing_args ))
238+ return
224239
225- result = self .make_request (api_name , args_dict , isAsync )
240+ result = self .make_request (apiname , args_dict ,
241+ apiname in self .apicache ['asyncapis' ])
226242 if result is None :
227243 return
228244 try :
@@ -248,27 +264,29 @@ def completedefault(self, text, line, begidx, endidx):
248264 search_string = ""
249265
250266 if separator != " " : # Complete verb subjects
251- autocompletions = self .cache_verbs [verb ].keys ()
267+ autocompletions = self .apicache [verb ].keys ()
252268 search_string = subject
253269 else : # Complete subject params
254270 autocompletions = map (lambda x : x + "=" ,
255- self .cache_verbs [verb ][subject ][1 ])
271+ map (lambda x : x ['name' ],
272+ self .apicache [verb ][subject ]['params' ]))
256273 search_string = text
257274
258275 if self .tabularize == "true" and subject != "" :
259276 autocompletions .append ("filter=" )
260277 return [s for s in autocompletions if s .startswith (search_string )]
261278
279+
262280 def do_sync (self , args ):
263281 """
264282 Asks cloudmonkey to discovery and sync apis available on user specified
265283 CloudStack host server which has the API discovery plugin, on failure
266284 it rollbacks last datastore or api precached datastore.
267285 """
268286 response = self .make_request ("listApis" )
269- f = open ( 'test.json' , "w" )
270- f . write ( json . dumps ( response ) )
271- f . close ()
287+ self . apicache = monkeycache ( response )
288+ savecache ( self . apicache , self . cache_file )
289+ self . loadcache ()
272290
273291 def do_api (self , args ):
274292 """
@@ -282,11 +300,6 @@ def do_api(self, args):
282300 else :
283301 self .monkeyprint ("Please use a valid syntax" )
284302
285- def complete_api (self , text , line , begidx , endidx ):
286- mline = line .partition (" " )[2 ]
287- offs = len (mline ) - len (text )
288- return [s [offs :] for s in completions if s .startswith (mline )]
289-
290303 def do_set (self , args ):
291304 """
292305 Set config for cloudmonkey. For example, options can be:
@@ -387,19 +400,22 @@ def do_EOF(self, args):
387400
388401
389402def main ():
390- pattern = re .compile ("[A-Z]" )
391- verbs = list (set ([x [:pattern .search (x ).start ()] for x in completions
392- if pattern .search (x ) is not None ]).difference (['cloudstack' ]))
403+ verbs = []
404+ if os .path .exists (cache_file ):
405+ verbs = loadcache (cache_file )['verbs' ]
406+ elif 'verbs' in apicache :
407+ verbs = apicache ['verbs' ]
408+
393409 for verb in verbs :
394410 def add_grammar (verb ):
395411 def grammar_closure (self , args ):
396412 if self .pipe_runner ("%s %s" % (verb , args )):
397413 return
398414 try :
399415 args_partition = args .partition (" " )
400- res = self .cache_verbs [verb ][args_partition [0 ]]
401- cmd = res [ 0 ]
402- helpdoc = res [ 2 ]
416+ api = self .apicache [verb ][args_partition [0 ]]
417+ cmd = api [ 'name' ]
418+ helpdoc = api [ 'description' ]
403419 args = args_partition [2 ]
404420 except KeyError , e :
405421 self .monkeyprint ("Error: invalid %s api arg" % verb , e )
@@ -412,10 +428,10 @@ def grammar_closure(self, args):
412428
413429 grammar_handler = add_grammar (verb )
414430 grammar_handler .__doc__ = "%ss resources" % verb .capitalize ()
415- grammar_handler .__name__ = 'do_' + verb
431+ grammar_handler .__name__ = 'do_' + str ( verb )
416432 setattr (CloudMonkeyShell , grammar_handler .__name__ , grammar_handler )
417433
418- shell = CloudMonkeyShell (sys .argv [0 ], verbs )
434+ shell = CloudMonkeyShell (sys .argv [0 ])
419435 if len (sys .argv ) > 1 :
420436 shell .onecmd (' ' .join (sys .argv [1 :]))
421437 else :
0 commit comments