import repository from arizona
[raven.git] / apps / mprepo / index.py
1 # /usr/bin/env python
2
3 import sys
4 sys.path.append("/usr/local/mprepo/bin")
5
6 import arizonaconfig
7 import arizonageneral
8 import arizonareport
9 import arizonatemplate
10
11 import mprfrontend
12 import repoclassify
13 import repoplc
14
15 import os
16 import repoconfig
17 import repobackend
18 import shutil
19 import tempfile
20 import time
21
22 import xmlrpclib
23
24 import planetlabAPI
25
26 from html import *
27 from repoauth import *
28
29 def get_slice_options(helper, slicedicts=None, current_slicename=None):
30    if not slicedicts:
31        slicedicts = helper.get_slices()
32
33    slice_options = ""
34    for slicedict in slicedicts:
35       slicename = slicedict["name"]
36       slicedisplayname = slicedict["displayname"]
37
38       slice_options = slice_options + "<option name='" + slicename +"'"
39
40       if current_slicename == slicename:
41          slice_options = slice_options + " selected"
42
43       slice_options = slice_options + ">" + slicedisplayname + "</option>"
44
45    return slice_options
46
47 def login(req):
48     helper = mprfrontend.PageHelper(req)
49
50     # only allow https access to the login page
51     if not helper.refuse_http():
52         return
53
54     logintypes = arizonaconfig.get_option("logintypes")
55     if len(logintypes) == 0:
56        return "No login types are enabled on this server.   You may not log in"
57
58     loginoptions = ""
59     default = True
60     for logintype in logintypes:
61         if "PLauthenticate" == logintype:
62             loginoptions += OPTION(logintype, default, "PlanetLab")
63         elif "PLEauthenticate" == logintype:
64             loginoptions += OPTION(logintype, default, "PlanetLab Eurpoe")
65         elif "passfileauthenticate" == logintype:
66             loginoptions += OPTION(logintype, default, "Passfile")
67         default = False
68
69     loginbody = ""
70
71     if loginoptions:
72         loginaccount = ""
73         loginaccount += "<h3>Login using an account</h3>"
74         loginaccount += TABLE(TR(TD("Site:") + TD(SELECT("authmethod", loginoptions))) + \
75                            TR(TD("Username:") + TD(INPUT("username"))) + \
76                            TR(TD("Password:") + TD(INPUT("password", type="password"))))
77         loginaccount += BUTTON("submit", "Login")
78         loginaccount = FORM("submit_auth", "POST", loginaccount)
79         loginbody += loginaccount
80
81
82     if "geniauthenticate" in logintype:
83         logingeni = ""
84         logingeni += "<br><h3>or<h3><br><h3>Login using a SFA gid/credential file</h3>"
85         logingeni += TABLE(TR(TD("Filename:") + TD(INPUT("genifile", type="file", size=None))))
86         logingeni += BUTTON("submit", "Login")
87         logingeni = FORM("submit_auth_geni", "POST", logingeni, enctype="multipart/form-data")
88         loginbody += logingeni
89
90     req.write( arizonatemplate.retrieve_template("loginpage.stemp", {'loginbody':loginbody}) )
91
92     helper.done()
93
94 def logout(req):
95     helper = mprfrontend.PageHelper(req)
96     helper.set_logged_in(False)
97     helper.redirect("/")
98     helper.done()
99
100 def submit_auth(req, username = None, password = None, authmethod = "PLauthenticate", statusonly=False, genifile=None):
101     helper = mprfrontend.PageHelper(req)
102
103     try:
104         do_auth(helper, username, password, authmethod, genifile)
105     except LoginError, e:
106         if statusonly:
107             req.write("Error: " + e.value)
108             helper.done()
109             return
110         else:
111             return helper.backpage(e.value)
112
113     if statusonly:
114         req.write("Success")
115         helper.done()
116         return
117     else:
118         # redirect the user back to the home page
119         helper.redirect("/")
120
121         helper.done()
122
123 def submit_auth_geni(req, genifile, statusonly=False):
124     helper = mprfrontend.PageHelper(req)
125
126     try:
127         do_auth_geni(helper, genifile)
128     except LoginError, e:
129         if statusonly:
130             req.write("Error: " + e.value)
131             helper.done()
132             return
133         else:
134             return helper.backpage(e.value)
135
136     if statusonly:
137         req.write("Success")
138         helper.done()
139         return
140     else:
141         # redirect the user back to the home page
142         helper.redirect("/")
143
144         helper.done()
145
146 def debug(req):
147     helper = mprfrontend.PageHelper(req)
148
149     cap = arizonareport.start_capture()
150     try:
151        repoconfig.dump_config()
152     finally:
153        capture_string = arizonareport.stop_capture(cap)
154
155     try:
156        f = open(os.path.join(repoconfig.repo_var_dir, "eventd.status"), "r")
157        eventdstatus = "event daemon status: \n" + f.read() + "\n"
158        f.close()
159     except (OSError, IOError):
160        eventdstatus = "\n\nevent daemon status: unknown\n"
161
162     debugInfo = "current time: " + str(time.time()) + " " + time.ctime(time.time()) + "\n"
163
164     debugInfo += "interpreter: " + str(req.interpreter) + "\n"
165     debugInfo += "uri: " + str(req.uri) + "\n"
166     debugInfo += "parsed_uri: " + str(req.parsed_uri) + "\n"
167
168     req.write( arizonatemplate.retrieve_template("header.stemp", {'TITLE':'Debug Information'}) + \
169            "<pre>" + debugInfo + "\n" + capture_string + "\n" + eventdstatus + "</pre>" + \
170            arizonatemplate.retrieve_template("footer.stemp") )
171
172     helper.done()
173
174 def storkcontrol(req, slice=None):
175     helper = mprfrontend.PageHelper(req)
176     if not helper.check_login():
177         return
178
179     if not helper.refuse_trailing_slash():
180         return
181
182     if (helper.get_loginkind()=="geni"):
183         return helper.backpage("Slice control is not yet implemented for geni login")
184
185     slicedicts = helper.get_slices()
186     if (not slice) and (slicedicts):
187         slice = slicedicts[0]["name"]
188
189     if not repoplc.is_slice_authorized(slice):
190         return helper.backpage("you are not authorized to view the slice " + str(slice))
191
192     dict = {}
193     dict['SLICEOPTIONS'] = get_slice_options(helper, slicedicts, slice)
194     dict['SLICENAME'] = str(slice)
195     dict['SLICESTATUS'] = repoplc.get_stork_initscript_status(slice)
196
197     req.write( arizonatemplate.retrieve_template("header.stemp", {'TITLE':'Slice Control'}) + \
198            arizonatemplate.retrieve_template("storkcontrol.stemp", dict) + \
199            arizonatemplate.retrieve_template("footer.stemp") )
200
201     helper.done
202
203 def set_stork_control(req, controlaction=None, slice=None):
204     helper = mprfrontend.PageHelper(req)
205     if not helper.check_login():
206         return
207
208     if not slice:
209        return helper.backpage("no slice was selected")
210
211     if not repoplc.is_slice_authorized(slice):
212        return helper.backpage("you are not authorized to view the slice " + slice)
213
214     try:
215         if (controlaction == "Start Stork"):
216            repoplc.start_stork(slice)
217         elif (controlaction == "Stop Stork"):
218            repoplc.stop_stork(slice)
219     except xmlrpclib.Fault, e:
220         if e.faultCode == 108:
221            return helper.backpage("A permission error occurred while attempting to" +
222                                   " set the slice initscript. This is probably a" +
223                                   " misconfiguration error at planetlab. Please" +
224                                   " contact us at stork@cs.arizona.edu and we will" +
225                                   " contact PLC and try to resolve the issue")
226         else:
227             raise
228
229
230     helper.redirect("storkcontrol?slice=" + slice)
231
232     helper.done()
233
234 def upload(req, legacy="false"):
235     helper = mprfrontend.PageHelper(req)
236     if not helper.check_login():
237         return
238
239     if not helper.refuse_trailing_slash():
240         return
241
242     #if (legacy=="True") and (helper.get_loginkind()=="geni"):
243     #    return helper.backpage("Legacy uploads are not yet implemented for geni login")
244
245     dict = {}
246
247     # the legacy upload page includes a box to input the slicename
248     if legacy == "True":
249        template_name = "uploadlegacy.stemp"
250        dict['SLICEOPTIONS'] = get_slice_options(helper)
251     else:
252        template_name = "uploadpage.stemp"
253
254     req.write( arizonatemplate.retrieve_template("header.stemp", {'TITLE':'Upload'}) + \
255            arizonatemplate.retrieve_template(template_name, dict) + \
256            arizonatemplate.retrieve_template("footer.stemp") )
257
258     helper.done()
259
260 def receive_uploaded_file(req, infile, ftype=None, slice=None, debug=False, statusonly=False):
261     helper = mprfrontend.PageHelper(req)
262     if not helper.check_login():
263         return
264
265     if not infile.filename:
266        return helper.backpage("Must provide a file")
267
268     # if no file type was passed in from the form, then figure it out from
269     # the filename
270     if ftype == None:
271        ftype = repoclassify.getFiletype(infile.filename)
272
273     outfile = open('/tmp/myfile', 'wb')
274     infile.file.seek(0)
275     while True:
276         data = infile.file.read(8192)\r
277         if not data:\r
278             break\r
279         outfile.write(data)\r
280     outfile.close()\r
281     infile.file.seek(0)\r
282
283     fdt, tmpfile_name = tempfile.mkstemp()
284     tmpfile = os.fdopen(fdt, 'wb')
285
286     shutil.copyfileobj(infile.file, tmpfile, 8192)
287     tmpfile.close()
288
289     # the filename the user wants is the basename (directory removed) from
290     # the upload filename. Windows filename may have forward slashes, so
291     # switch them around
292     desiredname = os.path.basename(infile.filename.replace("\\","/"))
293
294     file = {"srcname": tmpfile_name,
295             "type": ftype,
296             "desiredname": desiredname}
297
298     # if this is a legacy upload, then fill in the slice name
299     if slice:
300        # XXX: need to verify that user has access to slice
301        file['slice'] = slice
302
303     cap = None
304     debug_output = ""
305     if debug:
306        cap = arizonareport.start_capture()
307
308     try:
309        try:
310           repobackend.process_uploads([file])
311           status = "Successfully Uploaded"
312        except "foo": # Exception, e:
313           status = "Exception: " + str(e)
314     finally:
315        # make sure to close down output capture if it was requested
316        if cap:
317           debug_output = arizonareport.stop_capture(cap)
318
319     # in case the upload processor set the type for us, get it back so we
320     # can report to the user
321     ftype = file['type']
322
323     if os.path.exists(tmpfile_name):
324        os.remove(tmpfile_name)
325
326     if statusonly:
327        req.write(status)
328     else:
329        req.write( arizonatemplate.retrieve_template("header.stemp", {'TITLE':'Upload Status'}) + \
330               arizonatemplate.retrieve_template("uploadstatus.stemp", {'FILENAME':desiredname, 'STATUS':status, 'TYPE':ftype, 'DEBUG':debug_output}) + \
331               arizonatemplate.retrieve_template("footer.stemp") )
332
333     helper.done()
334
335 def browse(req):
336     helper = mprfrontend.PageHelper(req)
337     if not helper.check_login():
338         return
339
340     helper.backpage("the browse feature is not yet implemented\n")
341
342 def search(req):
343     helper = mprfrontend.PageHelper(req)
344
345     helper.backpage("the search feature is not yet implemented\n")
346
347
348 # GUI compatibility page: login.php
349 def login_php(req, username=None, password=None, authmethod="PLauthenticate", statusonly=True):
350    return submit_auth(req, username=username, password=password, authmethod=authmethod, statusonly=statusonly)
351
352 # GUI compatibility page: gui_getslices.php
353 def gui_getslices_php(req):
354    helper = mprfrontend.PageHelper(req)
355    slices = repoplc.get_slicenames()
356    req.write("\n".join(slices))
357
358 # GUI compatibility page: autosetup.php
359 def autosetup_php(req, slice=None, username=None, password=None, authmethod="PLauthenticate", nodes=None):
360    helper = mprfrontend.PageHelper(req)
361
362    if nodes:
363       # make sure nodes doesn't have any quotes in it
364       nodes = nodes.rstrip(' "').lstrip(' "')
365       # nodes should be a space-separated list, so split it up
366       nodes = nodes.split(" ")
367
368    if not slice:
369       return "Error: no slice specified"
370
371    if not username:
372       return "Error: no username specified"
373
374    if not password:
375       return "Error: no password specified"
376
377    try:
378        do_auth(helper, username=username, password=password, authmethod=authmethod)
379    except LoginError, e:
380       return "Login Error: " + e.value
381
382    try:
383       print "setting start script for", slice
384       repoplc.start_stork(slice)
385    except Exception, e:
386       return "Exception while setting initscript: " + str(e)
387
388    if nodes:
389       print "adding nodes for", slice, ":", str(nodes)
390       try:
391          repoplc.add_nodes(slice, nodes)
392       except Exception, e:
393          return "Exception while adding nodes: " + str(e)
394
395    req.write("Success")
396    helper.done()
397
398 # GUI compatibility page: upload_handler.php
399 def upload_handler_php(req, slice=None, type=None, numfiles=1, uploadbutton="Upload File", file_0=None, sel0=None, sel1=None, sel2=None, statusonly=True):
400    if not (type in "package", "tp", "pacman", "pk", "conf"):
401       return "bad type: " + type
402
403    return receive_uploaded_file(req, infile=file_0, slice=slice, statusonly=statusonly)
404
405 def showsession(req):
406     helper = mprfrontend.PageHelper(req)
407     session = helper.session
408
409     req.content_type = "text/plain"
410     req.write(str(session))
411
412 def index(req):
413     helper = mprfrontend.PageHelper(req)
414     if not helper.check_login():
415         return
416
417     name = helper.get_name()
418
419     req.write( arizonatemplate.retrieve_template("header.stemp", {'TITLE':'Repository'}) + \
420                arizonatemplate.retrieve_template("home.stemp", {'NAME':name}) + \
421                arizonatemplate.retrieve_template("footer.stemp", {}) )
422
423     helper.done()
424
425
426