1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
|
import logging
log = logging.getLogger(__name__)
from turbogears import controllers, expose, flash, identity, redirect, error_handler,validate
from func.overlord.client import Overlord, Minions
from funcweb.widget_automation import WidgetListFactory,RemoteFormAutomation,RemoteFormFactory
from funcweb.widget_validation import WidgetSchemaFactory
# it is assigned into method_display on every request
global_form = None
def validate_decorator_updater(validator_value=None):
"""
When we pass the global_form directly to
turbogears.validate it is not updated on
every request we should pass a callable
to trigger it ;)
@param :validator_value : Does nothing in the code
of validate it is passed but is irrelevant in our case
because we compute the global_form in the method_display
@return : the current form and schema to validate the
current input in cherrypy's request
"""
global global_form
return global_form
class Funcweb(object):
#preventing the everytime polling and getting
#func = Overlord("name") thing
func_cache={
'fc_object':None,#the fc = Overlord() thing,
'glob':None,
'minion_name':None,
'module_name':None,
'modules':None,
'minions':None,
'methods':None
}
#will be reused for widget validation
@expose(template="funcweb.templates.minions")
@identity.require(identity.not_anonymous())
def minions(self, glob='*'):
""" Return a list of our minions that match a given glob """
#make the cache thing
if self.func_cache['glob'] == glob:
minions = self.func_cache['minions']
else:
#we dont have it it is for first time so lets pull it
minions=Minions(glob).get_all_hosts()
self.func_cache['glob']=glob
self.func_cache['minions']=minions
return dict(minions=minions)
index = minions # start with our minion view, for now
@expose(template="funcweb.templates.minion")
@identity.require(identity.not_anonymous())
def minion(self, name="*", module=None, method=None):
""" Display module or method details for a specific minion.
If only the minion name is given, it will display a list of modules
for that minion. If a module is supplied, it will display a list of
methods.
"""
#if we have it in the cache
if self.func_cache['minion_name'] == name:
fc = self.func_cache['fc_object']
else:
fc = Overlord(name)
self.func_cache['fc_object']=fc
self.func_cache['minion_name']=name
#reset the children :)
self.func_cache['module_name']=None
self.func_cache['modules']=None
self.func_cache['methods']=None
#should also reset the other fields or not ?
if not module:
if not self.func_cache['modules']:
modules = fc.system.list_modules()
display_modules = []
for module in modules.itervalues():
for mod in module:
#if it is not empty
if getattr(fc,mod).get_method_args()[name]:
display_modules.append(mod)
#put it into the cache to make that slow thing faster
self.func_cache['modules']=display_modules
else:
#print "Im in the cache"
#just list those who have get_method_args
display_modules = self.func_cache['modules']
modules = {}
modules[name]=display_modules
return dict(modules=modules)
else: # a module is specified
if not method: # return a list of methods for specified module
#first check if we have it into the cache
if self.func_cache['module_name'] == module and self.func_cache['methods']:
modules = self.func_cache['methods']
#print "Im in the cache"
else:
self.func_cache['module_name']= module
#display the list only that is registered with register_method template !
registered_methods=getattr(fc,module).get_method_args()[name].keys()
modules = getattr(fc, module).list_methods()
for mods in modules.itervalues():
from copy import copy
cp_mods = copy(mods)
for m in cp_mods:
if not m in registered_methods:
mods.remove(m)
#store into cache if we get it again
self.func_cache['methods'] = modules
#display em
return dict(modules=modules, module=module,
tg_template="funcweb.templates.module")
else:
return "Wrong place :)"
@expose(template="funcweb.templates.method_args")
@identity.require(identity.not_anonymous())
def method_display(self,minion=None,module=None,method=None):
"""
That method generates the input widget for givent method.
"""
global global_form
if self.func_cache['minion_name'] == minion:
fc = self.func_cache['fc_object']
else:
fc = Overlord(minion)
self.func_cache['fc_object']=fc
self.func_cache['minion_name']=minion
#reset the children :)
self.func_cache['module_name']=module
self.func_cache['modules']=None
self.func_cache['methods']=None
#get the method args
method_args = getattr(fc,module).get_method_args()
if not method_args.values():
#print "Not registered method here"
return dict(minion_form = None,minion=minion,module=module,method=method)
minion_arguments = method_args[minion][method]['args']
#the description of the method we are going to display
if method_args[minion][method].has_key('description'):
description = method_args[minion][method]['description']
else:
description = None
if minion_arguments:
wlist_object = WidgetListFactory(minion_arguments,minion=minion,module=module,method=method)
wlist_object = wlist_object.get_widgetlist_object()
#create the validation parts for the remote form
wf = WidgetSchemaFactory(minion_arguments)
schema_man=wf.get_ready_schema()
#create the final form
minion_form = RemoteFormAutomation(wlist_object,schema_man)
global_form = minion_form.for_widget
#print global_form
#i use that when something goes wrong to check the problem better to stay here ;)
#self.minion_form =RemoteFormFactory(wlist_object,schema_man).get_remote_form()
del wlist_object
del minion_arguments
return dict(minion_form =minion_form,minion=minion,module=module,method=method,description=description)
else:
return dict(minion_form = None,minion=minion,module=module,method=method,description = description)
@expose(template="funcweb.templates.login")
def login(self, forward_url=None, previous_url=None, *args, **kw):
"""
The login form for not registered users
"""
from cherrypy import request, response
if not identity.current.anonymous \
and identity.was_login_attempted() \
and not identity.get_identity_errors():
raise redirect(forward_url)
forward_url=None
previous_url= request.path
if identity.was_login_attempted():
msg=_("The credentials you supplied were not correct or "
"did not grant access to this resource.")
elif identity.get_identity_errors():
msg=_("You must provide your credentials before accessing "
"this resource.")
else:
msg=_("Please log in.")
print "I use that thing here"
forward_url= request.headers.get("Referer", ".")
response.status=403
return dict(message=msg, previous_url=previous_url, logging_in=True,
original_parameters=request.params,
forward_url=forward_url)
@expose()
@identity.require(identity.not_anonymous())
def handle_minion_error(self,tg_errors=None):
"""
The method checks the result from turbogears.validate
decorator so if it has the tg_errors we know that the
form validation is failed. That prevents the extra traffic
to be sent to the minions!
"""
if tg_errors:
#print tg_errors
return str(tg_errors)
@expose(allow_json=True)
@error_handler(handle_minion_error)
@validate(form=validate_decorator_updater)
@identity.require(identity.not_anonymous())
def post_form(self,**kw):
"""
Data processing part for methods that accept some inputs.
Method recieves the method arguments for minion method then
orders them into their original order and sends the xmlrpc
request to the minion !
"""
if kw.has_key('minion') and kw.has_key('module') and kw.has_key('method'):
#assign them because we need the rest so dont control everytime
#and dont make lookup everytime ...
#the del statements above are important dont remove them :)
minion = kw['minion']
del kw['minion']
module = kw['module']
del kw['module']
method = kw['method']
del kw['method']
if self.func_cache['minion_name'] == minion:
fc = self.func_cache['fc_object']
else:
fc = Overlord(minion)
self.func_cache['fc_object']=fc
self.func_cache['minion_name']=minion
#reset the children :)
self.func_cache['module_name']=module
self.func_cache['modules']=None
self.func_cache['methods']=None
#get again the method args to get their order :
arguments=getattr(fc,module).get_method_args()
#so we know the order just allocate and put them there
cmd_args=['']*(len(kw.keys()))
for arg in kw.keys():
#wow what a lookup :)
index_of_arg = arguments[minion][method]['args'][arg]['order']
cmd_args[index_of_arg]=kw[arg]
#now execute the stuff
result = getattr(getattr(fc,module),method)(*cmd_args)
return str(result)
else:
return "Missing arguments sorry can not proceess the form"
@expose(template="funcweb.templates.method_args")
@identity.require(identity.not_anonymous())
def execute_link(self,minion=None,module=None,method=None):
"""
Method is fot those minion methods that dont accept any
arguments so they provide only some information,executed
by pressing only the link !
"""
if self.func_cache['minion_name'] == minion:
fc = self.func_cache['fc_object']
else:
fc = Overlord(minion)
self.func_cache['fc_object']=fc
self.func_cache['minion_name']=minion
#reset the children :)
self.func_cache['module_name']=module
self.func_cache['modules']=None
self.func_cache['methods']=None
result = getattr(getattr(fc,module),method)()
return str(result)
@expose()
def logout(self):
"""
The logoout part
"""
identity.current.logout()
raise redirect("/")
class Root(controllers.RootController):
@expose()
def index(self):
raise redirect("/funcweb")
index = index # start with our minion view, for now
funcweb = Funcweb()
|