def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) client_dir = client_id_dir(client_id) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) status = returnvalues.OK title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Job Manager' title_entry['style'] = css_tmpl(configuration) title_entry['javascript'] = js_tmpl() output_objects.append({'object_type': 'header', 'text': 'Job Manager'}) output_objects.append({'object_type': 'html_form', 'text': html_pre()}) output_objects.append({'object_type': 'table_pager', 'entry_name': 'jobs', 'default_entries': default_pager_entries, 'form_append': pager_append()}) output_objects.append({'object_type': 'html_form', 'text': html_post()}) return (output_objects, status)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = initialize_main_variables(client_id, op_header=False) output_objects.append({"object_type": "header", "text": "%s Virtual Desktop" % configuration.short_title}) status = returnvalues.OK defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) title_entry = find_entry(output_objects, "title") title_entry["text"] = "Virtual Machines" if not configuration.site_enable_vmachines: output_objects.append( { "object_type": "text", "text": """Virtual machines are disabled on this site. Please contact the Grid admins %s if you think they should be enabled. """ % configuration.admin_email, } ) return (output_objects, returnvalues.OK) settings_dict = load_settings(client_id, configuration) if not settings_dict or not settings_dict.has_key("VNCDISPLAY"): logger.info("Settings dict does not have VNCDISPLAY key - using default") (vnc_display_width, vnc_display_height) = (1024, 768) else: (vnc_display_width, vnc_display_height) = settings_dict["VNCDISPLAY"] # Make room for vnc control menu vnc_menu_height = 24 vnc_display_height += vnc_menu_height password = vms.vnc_jobid(accepted["job_id"][0]) # Do an "intoN" then map to acsii output_objects.append( { "object_type": "html_form", "text": vms.popup_snippet() + vms.vnc_applet(configuration, vnc_display_width, vnc_display_height, password), } ) return (output_objects, status)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) user_dir = os.path.join(configuration.user_home, client_id_dir(client_id)) title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'ARC Queues' output_objects.append({'object_type': 'header', 'text' : 'Available ARC queues'}) if not configuration.site_enable_griddk: output_objects.append({'object_type': 'text', 'text': '''Grid.dk features are disabled on this site. Please contact the Grid admins %s if you think they should be enabled. ''' % configuration.admin_email}) return (output_objects, returnvalues.OK) # could factor out from here, to be usable from outside if not configuration.arc_clusters: output_objects.append({'object_type': 'error_text', 'text': 'No ARC support!'}) return (output_objects, returnvalues.ERROR) try: session = arc.Ui(user_dir) queues = session.getQueues() except arc.NoProxyError, err: output_objects.append({'object_type': 'error_text', 'text' : 'Error while retrieving: %s' % err.what() }) output_objects += arc.askProxy() return (output_objects, returnvalues.ERROR)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] output_objects.append({'object_type': 'header', 'text' : 'Show runtime environment details'}) (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) re_name = accepted['re_name'][-1] if not valid_dir_input(configuration.re_home, re_name): logger.warning( "possible illegal directory traversal attempt re_name '%s'" % re_name) output_objects.append({'object_type': 'error_text', 'text' : 'Illegal runtime environment name: "%s"' % re_name}) return (output_objects, returnvalues.CLIENT_ERROR) if not is_runtime_environment(re_name, configuration): output_objects.append({'object_type': 'error_text', 'text' : "'%s' is not an existing runtime environment!" % re_name}) return (output_objects, returnvalues.CLIENT_ERROR) title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Runtime environment details' (re_dict, msg) = get_re_dict(re_name, configuration) if not re_dict: output_objects.append({'object_type': 'error_text', 'text' : 'Could not read details for "%s"' % msg}) return (output_objects, returnvalues.SYSTEM_ERROR) output_objects.append(build_reitem_object(configuration, re_dict)) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) client_dir = client_id_dir(client_id) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) status = returnvalues.OK all_paths = accepted['path'] entry_path = all_paths[-1] title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'File Manager' title_entry['style'] = css_tmpl(configuration) if 'submitjob' in extract_menu(configuration, title_entry): enable_submit = 'true' else: enable_submit = 'false' title_entry['javascript'] = js_tmpl(entry_path, enable_submit, str(configuration.site_enable_preview)) output_objects.append({'object_type': 'header', 'text': 'File Manager' }) output_objects.append({'object_type': 'html_form', 'text': html_tmpl(configuration, title_entry)}) if len(all_paths) > 1: output_objects.append({'object_type': 'sectionheader', 'text': 'All requested paths:'}) for path in all_paths: output_objects.append({'object_type': 'link', 'text': path, 'destination': 'fileman.py?path=%s' % path}) output_objects.append({'object_type': 'text', 'text': ''}) return (output_objects, status)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Resource details' output_objects.append({'object_type': 'header', 'text' : 'Show resource details'}) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) resource_list = accepted['unique_resource_name'] status = returnvalues.OK visible_res = user_visible_res_confs(configuration, client_id) allowed_vgrids = user_allowed_vgrids(configuration, client_id) for visible_res_name in resource_list: if not visible_res_name in visible_res.keys(): logger.warning('User %s not allowed to view %s (%s)' % \ (client_id, visible_res_name, visible_res.keys())) output_objects.append({'object_type': 'error_text', 'text': 'invalid resource %s' % \ visible_res_name}) continue res_dict = visible_res[visible_res_name] res_item = build_resitem_object_from_res_dict(configuration, visible_res_name, res_dict, allowed_vgrids) output_objects.append(res_item) return (output_objects, status)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) title_entry = find_entry(output_objects, 'title') title_entry['text'] = '%s send request' % \ configuration.short_title output_objects.append({'object_type': 'header', 'text' : 'Send request'}) output_objects.append({'object_type': 'warning', 'text' : ''' Remember that sending a membership or ownership request generates a message to the owners of the target. All requests are logged together with the ID of the submitter. Spamming and other abuse will not be tolerated!'''}) output_objects.append({'object_type': 'sectionheader', 'text' : 'Request %s membership/ownership' % \ configuration.site_vgrid_label}) output_objects.append({'object_type': 'html_form', 'text' : """ <form method='post' action='sendrequestaction.py'> <table align='center'> <tr><td>Request type</td><td><select name=request_type> <option value=vgridmember>%(_label)s membership</option> <option value=vgridowner>%(_label)s ownership</option> </select></td></tr> <tr><td> %(_label)s name </td><td><input name=vgrid_name /> </td></tr> <tr> <td>Reason (text to owners)</td><td><input name=request_text size=40 /></td> </tr> <tr><td><input type='submit' value='Submit' /></td><td></td></tr></table> </form>""" % {'_label': configuration.site_vgrid_label}}) output_objects.append({'object_type': 'sectionheader', 'text' : 'Request resource ownership'}) output_objects.append({'object_type': 'html_form', 'text' : """ <form method='post' action='sendrequestaction.py'> <table align='center'> <tr><td>Request type</td><td><select name=request_type> <option value=resourceowner>Resource ownership</option> </select></td></tr> <tr><td> Resource ID </td><td><input name=unique_resource_name /> </td></tr> <tr> <td>Reason (text to owners)</td><td><input name=request_text size=40 /></td> </tr> <tr><td><input type='submit' value='Submit' /></td><td></td></tr></table> </form>"""}) output_objects.append({'object_type': 'sectionheader', 'text' : 'Send message'}) protocol_options = '' for proto in [any_protocol] + configuration.notify_protocols: protocol_options += '<option value=%s>%s</option>\n' % (proto, proto) output_objects.append({'object_type': 'html_form', 'text' : """ <form method='post' action='sendrequestaction.py'> <table align='center'> <tr><td>Request type</td><td><select name=request_type> <option value=plain>Plain message</option> </select></td></tr> <tr><td> User ID </td><td><input name=cert_id size=50 /> </td></tr> <tr><td>Protocol</td><td><select name=protocol> %s </select></td></tr> <tr> <td>Message</td> <td><textarea name=request_text cols=72 rows=10 /></textarea></td> </tr> <tr><td><input type='submit' value='Send' /></td><td></td></tr></table> </form>""" % protocol_options}) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) client_dir = client_id_dir(client_id) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) # TODO: if validator is too tight we should accept rejects here # and then make sure that such rejected fields are never printed if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) path = accepted['path'][-1] current_dir = accepted['current_dir'][-1] # Please note that base_dir must end in slash to avoid access to other # user dirs when own name is a prefix of another user name base_dir = os.path.abspath(os.path.join(configuration.user_home, client_dir)) + os.sep # the client can choose to specify the path of the target directory with # current_dir + "/" + path, instead of specifying the complete path in # subdirs. This is usefull from ls.py where a hidden html control makes it # possible to target the directory from the current dir. title_entry = find_entry(output_objects, 'title') title_entry['text'] = '%s file web editor' % configuration.short_title title_entry['style'] = advanced_editor_css_deps() title_entry['javascript'] = advanced_editor_js_deps() title_entry['javascript'] += lock_info('this file', -1) output_objects.append({'object_type': 'header', 'text' : 'Editing file in %s home directory' % \ configuration.short_title }) if not path: now = time.gmtime() path = 'noname-%s.txt' % time.strftime('%d%m%y-%H%M%S', now) output_objects.append({'object_type': 'text', 'text' : 'No path supplied - creating new file in %s' % path}) path = os.path.normpath(current_dir + path) real_path = os.path.abspath(base_dir + current_dir + path) if not valid_user_path(real_path, base_dir): logger.warning('%s tried to %s restricted path %s ! (%s)' % (client_id, op_name, real_path, path)) output_objects.append( {'object_type': 'error_text', 'text' : "Invalid path! (%s expands to an illegal path)" % path}) return (output_objects, returnvalues.CLIENT_ERROR) (owner, time_left) = acquire_edit_lock(real_path, client_id) if owner == client_id: javascript = \ '''<script type="text/javascript"> setTimeout("newcountdown('%s', %d)", 1) </script> '''\ % (path, time_left / 60) output_objects.append({'object_type': 'html_form', 'text' : javascript}) html = edit_file(path, real_path) output_objects.append({'object_type': 'html_form', 'text' : html}) else: output_objects.append( {'object_type': 'error_text', 'text' : '%s acquired the editing lock for %s! (timeout in %d seconds)' % (owner, path, time_left)}) return (output_objects, returnvalues.CLIENT_ERROR) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False, op_menu=False) defaults = signature(configuration)[1] (validate_status, accepted) = validate_input(user_arguments_dict, defaults, output_objects, allow_rejects=False) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) valid_show = get_valid_topics(configuration) if keyword_all in accepted['show']: show = valid_show.keys() else: show = [i.lower() for i in accepted['show'] if i.lower() in valid_show] if not show: logger.info('%s showing default topics' % op_name) show = defaults['show'] openid_error = ', '.join(accepted['modauthopenid.error']) title_entry = find_entry(output_objects, 'title') title_entry['text'] = '%s login selector' % configuration.short_title # TODO: move ping to shared location for signup and login # TODO: wrap openid ping in function and split up for each oid title_entry['javascript'] = ''' <script type="text/javascript" src="/images/js/jquery.js"></script> <script type="text/javascript" src="/images/js/jquery.migtools.js"></script> <script type="text/javascript"> $(document).ready(function() { var action = "login", oid_title, oid_url, tag_prefix; oid_title = "KIT"; oid_url = "https://openid.ku.dk/id/"; tag_prefix = "kitoid_"; check_oid_available(action, oid_title, oid_url, tag_prefix); oid_title = "%s"; var oid_url = "https://%s:%s/openid/id/"; tag_prefix = "migoid_"; check_oid_available(action, oid_title, oid_url, tag_prefix); }); </script> ''' % (configuration.short_title, configuration.user_openid_show_address, configuration.user_openid_show_port) title_entry['skipmenu'] = True header_entry = {'object_type': 'header', 'text' : 'Welcome to the %s login selector page' % \ configuration.short_title} output_objects.append(header_entry) html = "" if openid_error: err_txt, report_txt = '', '' if 'no_idp_found' in openid_error: err_txt += "OpenID server did not respond!" report_txt += """It appears the requested OpenID login service is offline""" else: err_txt += "OpenID server error!" report_txt += """It appears there's a problem with the requested OpenID login service""" report_txt += """, so you cannot currently use it for login to %s.<br /> Please report the problem to your OpenID identity provider. """ % configuration.short_title html += """<h2>OpenID Login to %s Failed!</h2> <div class='errortext'> %s (error code(s): %s) </div> <div class='warningtext'> %s </div> """ % (configuration.short_title, err_txt, openid_error, report_txt) html += """<h2>Login to %s</h2> <p> There are multiple login methods as described below. </p> """ % configuration.short_title if configuration.user_openid_providers and 'kitoid' in show or \ 'migoid' in show: html += """<h2>OpenID</h2> The simplest login method is to use an existing OpenID login if you have one. """ if 'kitoid' in show: html += """ <p> If you are a KU user, your usual login for KU Net and KU webmail works for OpenID as well. </p> <div id='kitoid_status'> <!-- OpenID status updated by AJAX call --> </div> <div id='kitoid_debug'> <!-- OpenID debug updated by AJAX call --> </div> <div class='form_container'> <form method='post' action='%(kitoid_url)s'> <input id='kitoid_button' type='submit' value='Login with KU OpenID' /> </form> </div> """ if 'migoid' in show: html += """ <p> If you already have a MiG OpenID account here you can login to the account using the local MiG OpenID server. <div id='migoid_status'> <!-- OpenID status updated by AJAX call --> </div> <div id='migoid_debug'> <!-- OpenID debug updated by AJAX call --> </div> <div class='form_container'> <form method='post' action='%(migoid_url)s'> <input id='migoid_button' type='submit' value='Login with MiG OpenID' /> </form> </p> </div> """ html += """ <p> When you click the Login with OpenID button you will be taken to a login page, where you need to provide your credentials and accept that your identity is used for login with this site. </p> """ if 'extcert' in show: html += """ <h2>Client Certificate</h2> <p> We provide high security access control with client certificates, like the ones you may know from digital signature providers. </p> """ html += """ <p> If you have an x509 user certificate associated with your account you can login using it here. Depending on your certificate installation you may be prompted for a password. </p> <div class='form_container'> <form method='get' action='%(extcert_url)s'> <input id='reqcert_button' type='submit' value='Login with Your User Certificate' /> </form> </div> """ html += """ """ var_map = {'kitoid_url': valid_show['kitoid']['url'], 'migoid_url':valid_show['migoid']['url'], 'extcert_url': valid_show['extcert']['url'], } output_objects.append({'object_type': 'html_form', 'text': html % var_map}) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) status = returnvalues.OK defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) show_sandboxes = (accepted['show_sandboxes'][-1] != 'false') visible_exes = user_visible_res_exes(configuration, client_id) res_map = get_resource_map(configuration) anon_map = anon_to_real_res_map(configuration.resource_home) # Iterate through resources and show management for each one requested res_list = {'object_type': 'resource_list', 'resources': []} fields = ['PUBLICNAME', 'NODECOUNT', 'CPUCOUNT', 'MEMORY', 'DISK', 'ARCHITECTURE', 'SANDBOX', 'RUNTIMEENVIRONMENT'] # Leave the sorting to jquery tablesorter for visible_res_name in visible_exes.keys(): unique_resource_name = visible_res_name if visible_res_name in anon_map.keys(): unique_resource_name = anon_map[visible_res_name] if not show_sandboxes and sandbox_resource(unique_resource_name): continue res_obj = {'object_type': 'resource', 'name': visible_res_name} if client_id in res_map[unique_resource_name][OWNERS]: # Admin of resource when owner js_name = 'rmresowner%s' % hexlify(unique_resource_name) helper = html_post_helper(js_name, 'rmresowner.py', {'unique_resource_name': unique_resource_name, 'cert_id': client_id}) output_objects.append({'object_type': 'html_form', 'text': helper}) res_obj['resownerlink'] = \ {'object_type': 'link', 'destination': "javascript: confirmDialog(%s, '%s');"\ % (js_name, 'Really leave %s owners?' % \ unique_resource_name), 'class': 'removelink', 'title': 'Leave %s owners' % unique_resource_name, 'text': ''} res_obj['resdetailslink'] = \ {'object_type': 'link', 'destination': 'resadmin.py?unique_resource_name=%s'\ % unique_resource_name, 'class': 'adminlink', 'title': 'Administrate %s' % unique_resource_name, 'text': ''} else: # link to become owner js_name = 'reqresowner%s' % hexlify(unique_resource_name) helper = html_post_helper(js_name, 'sendrequestaction.py', {'unique_resource_name': visible_res_name, 'request_type': 'resourceowner', 'request_text': ''}) output_objects.append({'object_type': 'html_form', 'text': helper}) res_obj['resownerlink'] = \ {'object_type': 'link', 'destination': "javascript: confirmDialog(%s, '%s', '%s');"\ % (js_name, "Request ownership of " + \ visible_res_name + ":<br/>" + \ "\nPlease write a message to the owners (field below).", 'request_text'), 'class': 'addlink', 'title': 'Request ownership of %s' % visible_res_name, 'text': ''} res_obj['resdetailslink'] = \ {'object_type': 'link', 'destination': 'viewres.py?unique_resource_name=%s'\ % visible_res_name, 'class': 'infolink', 'title': 'View detailed %s specs' % \ visible_res_name, 'text': ''} # fields for everyone: public status for name in fields: res_obj[name] = res_map[unique_resource_name][CONF].get(name, '') # Use runtimeenvironment names instead of actual definitions res_obj['RUNTIMEENVIRONMENT'] = [i[0] for i in res_obj['RUNTIMEENVIRONMENT']] res_list['resources'].append(res_obj) title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Resource management' # jquery support for tablesorter and confirmation on "leave": title_entry['style'] = themed_styles(configuration) title_entry['javascript'] = ''' <script type="text/javascript" src="/images/js/jquery.js"></script> <script type="text/javascript" src="/images/js/jquery.tablesorter.js"></script> <script type="text/javascript" src="/images/js/jquery.tablesorter.pager.js"></script> <script type="text/javascript" src="/images/js/jquery.tablesorter.widgets.js"></script> <script type="text/javascript" src="/images/js/jquery-ui.js"></script> <script type="text/javascript" src="/images/js/jquery.confirm.js"></script> <script type="text/javascript" > $(document).ready(function() { // init confirmation dialog $( "#confirm_dialog" ).dialog( // see http://jqueryui.com/docs/dialog/ for options { autoOpen: false, modal: true, closeOnEscape: true, width: 500, buttons: { "Cancel": function() { $( "#" + name ).dialog("close"); } } }); // table initially sorted by col. 1 (admin), then 0 (name) var sortOrder = [[1,0],[0,0]]; // use image path for sorting if there is any inside var imgTitle = function(contents) { var key = $(contents).find("a").attr("class"); if (key == null) { key = $(contents).html(); } return key; } $("#resourcetable").tablesorter({widgets: ["zebra", "saveSort"], sortList:sortOrder, textExtraction: imgTitle }) .tablesorterPager({ container: $("#pager"), size: %s }); } ); </script> ''' % default_pager_entries output_objects.append({'object_type': 'html_form', 'text':''' <div id="confirm_dialog" title="Confirm" style="background:#fff;"> <div id="confirm_text"><!-- filled by js --></div> <textarea cols="40" rows="4" id="confirm_input" style="display:none;"></textarea> </div> ''' }) output_objects.append({'object_type': 'header', 'text': 'Available Resources' }) output_objects.append({'object_type': 'sectionheader', 'text' : 'Resources available on this server'}) output_objects.append({'object_type': 'text', 'text' : ''' All available resources are listed below with overall hardware specifications. Any resources that you own will have a administration icon that you can click to open resource management. ''' }) output_objects.append({'object_type': 'table_pager', 'entry_name': 'resources', 'default_entries': default_pager_entries}) output_objects.append(res_list) if configuration.site_enable_sandboxes: if show_sandboxes: output_objects.append({'object_type': 'link', 'destination': '?show_sandboxes=false', 'class': 'removeitemlink', 'title': 'Hide sandbox resources', 'text': 'Exclude sandbox resources', }) else: output_objects.append({'object_type': 'link', 'destination': '?show_sandboxes=true', 'class': 'additemlink', 'title': 'Show sandbox resources', 'text': 'Include sandbox resources', }) output_objects.append({'object_type': 'sectionheader', 'text' : 'Resource Status'}) output_objects.append({'object_type': 'text', 'text': ''' Live resource status is available in the resource monitor page with all %s/resources you can access ''' % configuration.site_vgrid_label}) output_objects.append({'object_type': 'link', 'destination': 'showvgridmonitor.py?vgrid_name=ALL', 'class': 'monitorlink', 'title': 'Show monitor with all resources you can access', 'text': 'Global resource monitor', }) output_objects.append({'object_type': 'sectionheader', 'text': 'Additional Resources' }) output_objects.append({'object_type': 'text', 'text': 'You can sign up spare or dedicated resources to the grid below.' }) output_objects.append({'object_type': 'link', 'destination' : 'resedit.py', 'class': 'addlink', 'title': 'Show sandbox resources', 'text': 'Create a new %s resource' % \ configuration.short_title, }) output_objects.append({'object_type': 'sectionheader', 'text': ''}) if configuration.site_enable_sandboxes: output_objects.append({'object_type': 'link', 'destination': 'ssslogin.py', 'class': 'adminlink', 'title': 'Administrate and monitor your sandbox resources', 'text': 'Administrate %s sandbox resources' % \ configuration.short_title, }) output_objects.append({'object_type': 'sectionheader', 'text': ''}) output_objects.append({'object_type': 'link', 'destination': 'oneclick.py', 'class': 'sandboxlink', 'title': 'Run a One-click resource in your browser', 'text': 'Use this computer as One-click %s resource' % \ configuration.short_title, }) return (output_objects, status)
for name in os.listdir(res_dir): file_path = os.path.join(res_dir, name) if os.path.isfile(file_path): os.unlink(file_path) except Exception, err: output_objects.append({'object_type': 'error_text', 'text' : 'Deletion exception: ' + str(err)}) output_objects.append({'object_type': 'link', 'destination': 'resman.py', 'class': 'infolink', 'title': 'Show resources', 'text': 'Show resources'}) lock_handle_vgrid.close() lock_handle_res.close() return (output_objects, returnvalues.CLIENT_ERROR) # The resource has been deleted, and OK is returned. title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Resource Deletion' output_objects.append({'object_type': 'header', 'text' : 'Deleting resource'}) output_objects.append({'object_type': 'text', 'text' : 'Sucessfully deleted resource: ' + resource_id}) output_objects.append({'object_type': 'link', 'destination': 'resman.py', 'class': 'infolink', 'title': 'Show resources', 'text': 'Show resources'}) # Releasing locks lock_handle_vgrid.close() lock_handle_res.close() # Remove resource from resource and vgrid caches (after realeasing locks) unmap_resource(configuration, resource_id)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] title_entry = find_entry(output_objects, 'title') label = "%s" % configuration.site_vgrid_label title_entry['text'] = "Reject %s Request" % label output_objects.append({ 'object_type': 'header', 'text': 'Reject %s Request' % label }) (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) vgrid_name = accepted['vgrid_name'][-1].strip() request_name = unhexlify(accepted['request_name'][-1]) if not safe_handler(configuration, 'post', op_name, client_id, get_csrf_limit(configuration), accepted): output_objects.append({ 'object_type': 'error_text', 'text': '''Only accepting CSRF-filtered POST requests to prevent unintended updates''' }) return (output_objects, returnvalues.CLIENT_ERROR) # Validity of user and vgrid names is checked in this init function so # no need to worry about illegal directory traversal through variables (ret_val, msg, ret_variables) = \ init_vgrid_script_add_rem(vgrid_name, client_id, request_name, 'request', configuration) if not ret_val: output_objects.append({'object_type': 'error_text', 'text': msg}) return (output_objects, returnvalues.CLIENT_ERROR) elif msg: # In case of warnings, msg is non-empty while ret_val remains True output_objects.append({'object_type': 'warning', 'text': msg}) if request_name: request_dir = os.path.join(configuration.vgrid_home, vgrid_name) req = load_access_request(configuration, request_dir, request_name) if not req or not delete_access_request(configuration, request_dir, request_name): logger.error("failed to delete owner request for %s in %s" % \ (vgrid_name, request_name)) output_objects.append({ 'object_type': 'error_text', 'text': 'Failed to remove saved vgrid request for %s in %s!'\ % (vgrid_name, request_name)}) return (output_objects, returnvalues.CLIENT_ERROR) output_objects.append({ 'object_type': 'text', 'text': ''' Deleted %(request_type)s access request to %(target)s for %(entity)s . ''' % req }) if req['request_type'] == 'vgridresource': id_field = "unique_resource_name" else: id_field = "cert_id" form_method = 'post' csrf_limit = get_csrf_limit(configuration) fill_helpers = { 'protocol': any_protocol, 'id_field': id_field, 'vgrid_label': label, 'form_method': form_method, 'csrf_field': csrf_field, 'csrf_limit': csrf_limit } fill_helpers.update(req) target_op = 'sendrequestaction' csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) fill_helpers.update({'target_op': target_op, 'csrf_token': csrf_token}) output_objects.append({ 'object_type': 'html_form', 'text': """ <p> You can use the reply form below if you want to additionally send an explanation for rejecting the request. </p> <form method='%(form_method)s' action='%(target_op)s.py'> <input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' /> <input type=hidden name=request_type value='vgridreject' /> <input type=hidden name=vgrid_name value='%(target)s' /> <input type=hidden name=%(id_field)s value='%(entity)s' /> <input type=hidden name=protocol value='%(protocol)s' /> <table> <tr> <td class='title'>Optional reject message to requestor(s)</td> </tr><tr> <td><textarea name=request_text cols=72 rows=10> We have decided to reject your %(request_type)s request to our %(target)s %(vgrid_label)s. Regards, the %(target)s %(vgrid_label)s owners </textarea></td> </tr> <tr> <td><input type='submit' value='Inform requestor(s)' /></td> </tr> </table> </form> <br /> """ % fill_helpers }) output_objects.append({ 'object_type': 'link', 'destination': 'adminvgrid.py?vgrid_name=%s' % vgrid_name, 'text': 'Back to administration for %s' % vgrid_name }) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) client_dir = client_id_dir(client_id) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) width = accepted['width'][-1] height = accepted['height'][-1] depth = accepted['depth'][-1] desktopname = accepted['desktopname'][-1] # Please note that base_dir must end in slash to avoid access to other # user dirs when own name is a prefix of another user name base_dir = os.path.abspath( os.path.join(configuration.user_home, client_dir)) + os.sep status = returnvalues.OK add_init = ''' function endVNC () { if (!window.XMLHttpRequest) var httpRequest = new ActiveXObject("Microsoft.XMLHTTP"); else var httpRequest = new XMLHttpRequest(); try { httpRequest.open("POST", "vncstop.py", ""); httpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); httpRequest.send(""); } catch (e) { alert(e); return e; } } ''' # ## TODO: Include something like the following for support for interactive jobrequests! # =============================================================================== # function submitjob(request) { # if (!window.XMLHttpRequest) # var httpRequest = new ActiveXObject("Microsoft.XMLHTTP"); # else # var httpRequest = new XMLHttpRequest(); # try { # httpRequest.open('POST', 'textarea.py', ''); # httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); # httpRequest.send(request); # } # catch (e) { # alert(e); # return e; # } # if (httpRequest.status == 200) # return httpRequest.responseText; # else # return httpRequest.status + " " + httpRequest.statusText; # } # ##############################################################333 # ....FOLLOWING IS A SAMPLE TAKEN FROM: dsl.gymer.dk (thx. for sharing gymer) # ....function submitkey() { # .... var form = document.getElementById("submitkeyform"); # .... var res = submitjob("action=submitkey"+"&key="+form.key.value ); # .... document.getElementById("subcontent").innerHTML = res; # ....} # =============================================================================== title_entry = find_entry(output_objects, 'title') title_entry['text'] = '%s Interactive Session' % configuration.short_title title_entry['script']['init'] = add_init title_entry['script']['body'] = 'onUnLoad="endVNC()"' output_objects.append({ 'object_type': 'header', 'text': 'Session for: %s' % client_id }) error = '' # Find available port/display. # TODO: Separate port and display no... Check /tmp/.X11-lock/ for available displays # ....and make bind check for available ports! Display might be in use without # ....using a port and vice-versa! passwdfile = '' password = '' valid_display_found = False (stat, msg) = get_users_display_dict(client_id, configuration, logger) if stat == False: output_objects.append({ 'object_type': 'error_text', 'text': 'Error getting dictionary of live displays %s' % msg }) status = returnvalues.CLIENT_ERROR return (output_objects, status) if stat == -1: logger.info('no existing display number for %s - creating' % client_id) baseVNCport = configuration.job_vnc_ports[0] VNC_port_count = len(configuration.job_vnc_ports) display_number = 1 start_display = 5 for i in range(start_display, VNC_port_count + start_display): free_display_found = False try: S = socket.socket() S.bind(('', baseVNCport + i)) display_number = i vnc_port = baseVNCport + display_number free_display_found = True except Exception, exc: error = exc S.close() S = None if free_display_found: # verify display is free or steal it? verify for now (disp_numb_stat, disp_numb_ret) = \ get_dict_from_display_number(i, configuration, logger) if disp_numb_stat == False: output_objects.append({ 'object_type': 'error_text', 'text': 'Error getting dictionary for display %s' % disp_numb_ret }) status = returnvalues.CLIENT_ERROR return (output_objects, status) if disp_numb_ret != -1: # display is registered as being in use, but the display seems to be available. continue else: # display is available (passstat, passmsg) = create_vnc_password() if passstat == False: output_objects.append({ 'object_type': 'error_text', 'text': passmsg }) status = returnvalues.CLIENT_ERROR logger.error('%s' % passmsg) return (output_objects, status) (password, passwdfile) = passmsg valid_display_found = True (stat, msg) = set_user_display_active( client_id, display_number, vnc_port, password, configuration, logger, ) if not stat: output_objects.append({ 'object_type': 'error_text', 'text': 'could not set user display active: %s' % msg }) status = returnvalues.CLIENT_ERROR return (output_objects, status) break
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) client_dir = client_id_dir(client_id) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) flags = ''.join(accepted['flags']) dst = accepted['dst'][-1].lstrip(os.sep) pattern_list = accepted['src'] if not safe_handler(configuration, 'post', op_name, client_id, get_csrf_limit(configuration), accepted): output_objects.append( {'object_type': 'error_text', 'text': '''Only accepting CSRF-filtered POST requests to prevent unintended updates''' }) return (output_objects, returnvalues.CLIENT_ERROR) # Please note that base_dir must end in slash to avoid access to other # user dirs when own name is a prefix of another user name base_dir = os.path.abspath(os.path.join(configuration.user_home, client_dir)) + os.sep title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Zip/tar archive extractor' output_objects.append({'object_type': 'header', 'text' : 'Zip/tar archive extractor'}) if verbose(flags): for flag in flags: output_objects.append({'object_type': 'text', 'text' : '%s using flag: %s' % (op_name, flag)}) if 'h' in flags: usage(output_objects) # IMPORTANT: path must be expanded to abs for proper chrooting abs_dest = os.path.abspath(os.path.join(base_dir, dst)) logger.info('unpack in %s' % abs_dest) # Don't use real dest in output as it may expose underlying # fs layout. relative_dest = abs_dest.replace(base_dir, '') if not valid_user_path(configuration, abs_dest, base_dir, True): # out of bounds logger.error('%s tried to %s restricted path %s ! (%s)' % (client_id, op_name, abs_dest, dst)) output_objects.append( {'object_type': 'error_text', 'text' : "Invalid path! (%s expands to an illegal path)" % dst}) return (output_objects, returnvalues.CLIENT_ERROR) if not check_write_access(abs_dest, parent_dir=True): logger.warning('%s called without write access: %s' % \ (op_name, abs_dest)) output_objects.append( {'object_type': 'error_text', 'text': 'cannot unpack to "%s": inside a read-only location!' % \ relative_dest}) return (output_objects, returnvalues.CLIENT_ERROR) status = returnvalues.OK for pattern in pattern_list: # Check directory traversal attempts before actual handling to avoid # leaking information about file system layout while allowing # consistent error messages unfiltered_match = glob.glob(base_dir + pattern) match = [] for server_path in unfiltered_match: # IMPORTANT: path must be expanded to abs for proper chrooting abs_path = os.path.abspath(server_path) if not valid_user_path(configuration, abs_path, base_dir, True): logger.warning('%s tried to %s restricted path %s ! (%s)' % (client_id, op_name, abs_path, pattern)) continue match.append(abs_path) # Now actually treat list of allowed matchings and notify if no # (allowed) match if not match: output_objects.append({'object_type': 'file_not_found', 'name': pattern}) status = returnvalues.FILE_NOT_FOUND for abs_path in match: relative_path = abs_path.replace(base_dir, '') if verbose(flags): output_objects.append({'object_type': 'file', 'name' : relative_path}) (unpack_status, msg) = unpack_archive(configuration, client_id, relative_path, relative_dest) if not unpack_status: output_objects.append({'object_type': 'error_text', 'text': 'Error: %s' % msg}) status = returnvalues.CLIENT_ERROR continue output_objects.append( {'object_type': 'text', 'text' : 'The zip/tar archive %s was unpacked in %s' % (relative_path, relative_dest)}) return (output_objects, status)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) action = accepted['action'][-1] req_list = accepted['req_id'] job_list = accepted['job_id'] lines = int(accepted['lines'][-1]) meta = '''<meta http-equiv="refresh" content="%s" /> ''' % configuration.sleep_secs title_entry = find_entry(output_objects, 'title') title_entry['text'] = '%s administration panel' % configuration.short_title title_entry['meta'] = meta # jquery support for tablesorter and confirmation on "remove" # table initially sorted by col. 9 (created) table_spec = {'table_id': 'accountreqtable', 'sort_order': '[[9,0]]'} (add_import, add_init, add_ready) = man_base_js(configuration, [table_spec]) title_entry['script']['advanced'] += add_import title_entry['script']['init'] += add_init title_entry['script']['ready'] += add_ready output_objects.append({ 'object_type': 'html_form', 'text': man_base_html(configuration) }) if not is_admin(client_id, configuration, logger): output_objects.append({ 'object_type': 'error_text', 'text': 'You must be an admin to access this control panel.' }) return (output_objects, returnvalues.CLIENT_ERROR) html = '' if action and not action in grid_actions.keys() + accountreq_actions: output_objects.append({ 'object_type': 'error_text', 'text': 'Invalid action: %s' % action }) return (output_objects, returnvalues.SYSTEM_ERROR) if action in grid_actions: msg = "%s" % grid_actions[action] if job_list: msg += ' %s' % ' '.join(job_list) msg += '\n' if not send_message_to_grid_script(msg, logger, configuration): output_objects.append({ 'object_type': 'error_text', 'text': '''Error sending %s message to grid_script.''' % action }) status = returnvalues.SYSTEM_ERROR elif action in accountreq_actions: if action == "addaccountreq": for req_id in req_list: if accept_account_req(req_id, configuration): output_objects.append({ 'object_type': 'text', 'text': 'Accepted account request %s' % req_id }) else: output_objects.append({ 'object_type': 'error_text', 'text': 'Accept account request failed - details in log' }) elif action == "delaccountreq": for req_id in req_list: if delete_account_req(req_id, configuration): output_objects.append({ 'object_type': 'text', 'text': 'Deleted account request %s' % req_id }) else: output_objects.append({ 'object_type': 'error_text', 'text': 'Delete account request failed - details in log' }) show, drop = '', '' general = """ <h2>Server Status</h2> <p class='importanttext'> This page automatically refreshes every %s seconds. </p> <p> You can see the current grid daemon status and server logs below. The buttons provide access to e.g. managing the grid job queues. </p> <form method='get' action='migadmin.py'> <input type='hidden' name='action' value='' /> <input type='submit' value='Show last log lines' /> <input type='text' size='2' name='lines' value='%s' /> </form> <br /> <form method='get' action='migadmin.py'> <input type='hidden' name='lines' value='%s' /> <input type='hidden' name='action' value='reloadconfig' /> <input type='submit' value='Reload Configuration' /> </form> <br /> """ % (configuration.sleep_secs, lines, lines) show += """ <form method='get' action='migadmin.py'> <input type='hidden' name='lines' value='%s' /> <input type='submit' value='Log Jobs' /> <select name='action'> """ % lines drop += """ <form method='get' action='migadmin.py'> <input type='hidden' name='lines' value='%s' /> <input type='submit' value='Drop Job' /> <select name='action'> """ % lines for queue in ['queued', 'executing', 'done']: selected = '' if action.find(queue) != -1: selected = 'selected' show += "<option %s value='show%s'>%s</option>" % (selected, queue, queue) drop += "<option %s value='drop%s'>%s</option>" % (selected, queue, queue) show += """ </select> </form> <br /> """ drop += """ </select> <input type='text' size='20' name='job_id' value='' /> </form> <br /> """ html += general html += show html += drop daemons = """ <div id='daemonstatus'> """ daemon_names = [] if configuration.site_enable_jobs: daemon_names += ['grid_script.py', 'grid_monitor.py', 'grid_sshmux.py'] if configuration.site_enable_events: daemon_names.append('grid_events.py') # No need to run im_notify unless any im notify protocols are enabled if configuration.site_enable_imnotify and \ [i for i in configuration.notify_protocols if i != 'email']: daemon_names.append('grid_imnotify.py') if configuration.site_enable_sftp: daemon_names.append('grid_sftp.py') if configuration.site_enable_davs: daemon_names.append('grid_webdavs.py') if configuration.site_enable_ftps: daemon_names.append('grid_ftps.py') if configuration.site_enable_openid: daemon_names.append('grid_openid.py') if configuration.site_enable_transfers: daemon_names.append('grid_transfers.py') if configuration.site_enable_crontab: daemon_names.append('grid_cron.py') if configuration.site_enable_seafile: daemon_names += [ 'seafile-controller', 'seaf-server', 'ccnet-server', 'seahub' ] if configuration.seafile_mount: daemon_names.append('seaf-fuse') if configuration.site_enable_sftp_subsys: daemon_names.append( '/sbin/sshd -f /etc/ssh/sshd_config-MiG-sftp-subsys') for proc in daemon_names: # NOTE: we use command list here to avoid shell requirement pgrep_proc = subprocess_popen(['pgrep', '-f', proc], stdout=subprocess_pipe, stderr=subprocess_stdout) pgrep_proc.wait() ps_out = pgrep_proc.stdout.read().strip() if pgrep_proc.returncode == 0: daemons += "<div class='status_online'>%s running (pid %s)</div>" \ % (proc, ps_out) else: daemons += "<div class='status_offline'>%s not running!</div>" % \ proc daemons += """</div> <br /> """ html += daemons output_objects.append({ 'object_type': 'header', 'text': 'Pending Certificate Requests' }) (list_status, ret) = list_account_reqs(configuration) if not list_status: logger.error("%s: failed for '%s': %s" % (op_name, client_id, ret)) output_objects.append({'object_type': 'error_text', 'text': ret}) return (output_objects, returnvalues.SYSTEM_ERROR) form_method = 'post' csrf_limit = get_csrf_limit(configuration) target_op = 'migadmin' csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) accountreqs = [] for req_id in ret: (load_status, req_dict) = get_account_req(req_id, configuration) if not load_status: logger.error("%s: load failed for '%s': %s" % (op_name, req_id, req_dict)) output_objects.append({ 'object_type': 'error_text', 'text': 'Could not read details for "%s"' % req_id }) return (output_objects, returnvalues.SYSTEM_ERROR) req_item = build_accountreqitem_object(configuration, req_dict) js_name = 'create%s' % req_id helper = html_post_helper(js_name, '%s.py' % target_op, { 'action': 'addaccountreq', 'req_id': req_id, csrf_field: csrf_token }) output_objects.append({'object_type': 'html_form', 'text': helper}) req_item['addaccountreqlink'] = { 'object_type': 'link', 'destination': "javascript: confirmDialog(%s, '%s');" % (js_name, 'Really accept %s?' % req_id), 'class': 'addlink iconspace', 'title': 'Accept %s' % req_id, 'text': '' } js_name = 'delete%s' % req_id helper = html_post_helper(js_name, '%s.py' % target_op, { 'action': 'delaccountreq', 'req_id': req_id, csrf_field: csrf_token }) output_objects.append({'object_type': 'html_form', 'text': helper}) req_item['delaccountreqlink'] = { 'object_type': 'link', 'destination': "javascript: confirmDialog(%s, '%s');" % (js_name, 'Really remove %s?' % req_id), 'class': 'removelink iconspace', 'title': 'Remove %s' % req_id, 'text': '' } accountreqs.append(req_item) output_objects.append({ 'object_type': 'table_pager', 'entry_name': 'pending certificate/OpenID account requests', 'default_entries': default_pager_entries }) output_objects.append({ 'object_type': 'accountreqs', 'accountreqs': accountreqs }) log_path_list = [] if os.path.isabs(configuration.logfile): log_path_list.append(configuration.logfile) else: log_path_list.append( os.path.join(configuration.log_dir, configuration.logfile)) for log_path in log_path_list: html += ''' <h2>%s</h2> <textarea class="fillwidth padspace" rows=%s readonly="readonly"> ''' % (log_path, lines) log_lines = read_tail(log_path, lines, logger) html += ''.join(log_lines[-lines:]) html += '''</textarea> ''' output_objects.append({'object_type': 'html_form', 'text': html}) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) status = returnvalues.OK defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) if not configuration.site_enable_jobs: output_objects.append({ 'object_type': 'error_text', 'text': '''Job execution is not enabled on this system''' }) return (output_objects, returnvalues.SYSTEM_ERROR) title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Manage jobs' output_objects.append({'object_type': 'header', 'text': 'Manage Jobs'}) output_objects.append({ 'object_type': 'sectionheader', 'text': 'View status of all submitted jobs' }) output_objects.append({ 'object_type': 'html_form', 'text': ''' <form method="get" action="jobstatus.py"> Sort by modification time: <input type="radio" name="flags" value="sv" />yes <input type="radio" name="flags" checked="checked" value="vi" />no<br /> <input type="hidden" name="job_id" value="*" /> <input type="hidden" name="output_format" value="html" /> <input type="submit" value="Show All" /> </form> ''' }) output_objects.append({ 'object_type': 'sectionheader', 'text': 'View status of individual jobs' }) output_objects.append({ 'object_type': 'html_form', 'text': ''' Filter job IDs (* and ? wildcards are supported)<br /> <form method="get" action="jobstatus.py"> Job ID: <input type="text" name="job_id" value="*" size="30" /><br /> Show only <input type="text" name="max_jobs" size="6" value=5 /> first matching jobs<br /> Sort by modification time: <input type="radio" name="flags" checked="checked" value="vsi" />yes <input type="radio" name="flags" value="vi" />no<br /> <input type="hidden" name="output_format" value="html" /> <input type="submit" value="Show" /> </form> ''' }) output_objects.append({ 'object_type': 'sectionheader', 'text': 'Resubmit job' }) form_method = 'post' csrf_limit = get_csrf_limit(configuration) fill_helpers = { 'short_title': configuration.short_title, 'form_method': form_method, 'csrf_field': csrf_field, 'csrf_limit': csrf_limit } target_op = 'resubmit' csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) fill_helpers.update({'target_op': target_op, 'csrf_token': csrf_token}) output_objects.append({ 'object_type': 'html_form', 'text': ''' <form method="%(form_method)s" action="%(target_op)s.py"> <input type="hidden" name="%(csrf_field)s" value="%(csrf_token)s" /> Job ID: <input type="text" name="job_id" size="30" /><br /> <input type="hidden" name="output_format" value="html" /> <input type="submit" value="Submit" /> </form> ''' % fill_helpers }) output_objects.append({ 'object_type': 'sectionheader', 'text': 'Freeze pending job' }) target_op = 'jobaction' csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) fill_helpers.update({'target_op': target_op, 'csrf_token': csrf_token}) output_objects.append({ 'object_type': 'html_form', 'text': ''' <form method="%(form_method)s" action="%(target_op)s.py"> <input type="hidden" name="%(csrf_field)s" value="%(csrf_token)s" /> Job ID: <input type="text" name="job_id" size="30" /><br /> <input type="hidden" name="action" value="freeze" /> <input type="hidden" name="output_format" value="html" /> <input type="submit" value="Freeze job" /> </form> ''' % fill_helpers }) output_objects.append({ 'object_type': 'sectionheader', 'text': 'Thaw frozen job' }) output_objects.append({ 'object_type': 'html_form', 'text': ''' <form method="%(form_method)s" action="%(target_op)s.py"> <input type="hidden" name="%(csrf_field)s" value="%(csrf_token)s" /> Job ID: <input type="text" name="job_id" size="30" /><br /> <input type="hidden" name="action" value="thaw" /> <input type="hidden" name="output_format" value="html" /> <input type="submit" value="Thaw job" /> </form> ''' % fill_helpers }) output_objects.append({ 'object_type': 'sectionheader', 'text': 'Cancel pending or executing job' }) output_objects.append({ 'object_type': 'html_form', 'text': ''' <form method="%(form_method)s" action="%(target_op)s.py"> <input type="hidden" name="%(csrf_field)s" value="%(csrf_token)s" /> Job ID: <input type="text" name="job_id" size="30" /><br /> <input type="hidden" name="action" value="cancel" /> <input type="hidden" name="output_format" value="html" /> <input type="submit" value="Cancel job" /> </form> ''' % fill_helpers }) output_objects.append({ 'object_type': 'sectionheader', 'text': 'Request live I/O' }) output_objects.append({ 'object_type': 'html_form', 'text': ''' <form method="get" action="liveio.py"> Job ID: <input type="text" name="job_id" size="30" /><br /> <input type="hidden" name="output_format" value="html" /> <input type="submit" value="Request" /> </form> <br /> ''' }) return (output_objects, status)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) unique_res_names = accepted['unique_resource_name'] if not configuration.site_enable_resources: output_objects.append({ 'object_type': 'error_text', 'text': '''Resources are not enabled on this system''' }) return (output_objects, returnvalues.SYSTEM_ERROR) # prepare for confirm dialog, tablesort and toggling the views (css/js) title_entry = find_entry(output_objects, 'title') title_entry['text'] = "Resource Administration" # jquery support for tablesorter and confirmation on request and leave # requests table initially sorted by 4, 3 (date first and with alphabetical # client ID) table_specs = [{ 'table_id': 'accessrequeststable', 'pager_id': 'accessrequests_pager', 'sort_order': '[[4,0],[3,0]]' }] (add_import, add_init, add_ready) = man_base_js(configuration, table_specs, {'width': 600}) add_init += ''' var toggleHidden = function(classname) { // classname supposed to have a leading dot $(classname).toggleClass("hidden"); }; /* helper for dynamic form input fields */ function onOwnerInputChange() { makeSpareFields("#dynownerspares", "cert_id"); } ''' add_ready += ''' /* init add owners form with dynamic input fields */ onOwnerInputChange(); $("#dynownerspares").on("blur", "input[name=cert_id]", function(event) { //console.debug("in add owner blur handler"); onOwnerInputChange(); } ); ''' title_entry['script']['advanced'] += add_import title_entry['script']['init'] += add_init title_entry['script']['ready'] += add_ready output_objects.append({ 'object_type': 'html_form', 'text': man_base_html(configuration) }) form_method = 'post' csrf_limit = get_csrf_limit(configuration) fill_helpers = { 'short_title': configuration.short_title, 'vgrid_label': configuration.site_vgrid_label, 'form_method': form_method, 'csrf_field': csrf_field, 'csrf_limit': csrf_limit } (re_stat, re_list) = list_runtime_environments(configuration) if not re_stat: logger.warning('Failed to load list of runtime environments') output_objects.append({ 'object_type': 'error_text', 'text': 'Error getting list of runtime environments' }) return (output_objects, returnvalues.SYSTEM_ERROR) output_objects.append({'object_type': 'header', 'text': 'Manage Resource'}) output_objects.append({ 'object_type': 'sectionheader', 'text': '%(short_title)s Resources Owned' % fill_helpers }) quick_links = [{ 'object_type': 'text', 'text': 'Quick links to all your resources and individual management' }] quick_links.append({ 'object_type': 'html_form', 'text': '<div class="hidden quicklinks">' }) quick_links.append({ 'object_type': 'link', 'destination': "javascript:toggleHidden('.quicklinks');", 'class': 'removeitemlink iconspace', 'title': 'Toggle view', 'text': 'Hide quick links' }) quick_links.append({'object_type': 'text', 'text': ''}) quick_res = {} quick_links_index = len(output_objects) output_objects.append({'object_type': 'sectionheader', 'text': ''}) owned = 0 res_map = get_resource_map(configuration) for unique_resource_name in res_map.keys(): if sandbox_resource(unique_resource_name): continue owner_list = res_map[unique_resource_name][OWNERS] resource_config = res_map[unique_resource_name][CONF] visible_res_name = res_map[unique_resource_name][RESID] if client_id in owner_list: quick_res[unique_resource_name] = { 'object_type': 'multilinkline', 'links': [{ 'object_type': 'link', 'destination': '?unique_resource_name=%s' % unique_resource_name, 'class': 'adminlink iconspace', 'title': 'Manage %s' % unique_resource_name, 'text': 'Manage %s' % unique_resource_name, }, { 'object_type': 'link', 'destination': 'viewres.py?unique_resource_name=%s' % visible_res_name, 'class': 'infolink iconspace', 'title': 'View %s' % unique_resource_name, 'text': 'View %s' % unique_resource_name, }] } if unique_resource_name in unique_res_names: raw_conf_file = os.path.join(configuration.resource_home, unique_resource_name, 'config.MiG') try: filehandle = open(raw_conf_file, 'r') raw_conf = filehandle.readlines() filehandle.close() except: raw_conf = [''] res_html = display_resource(client_id, unique_resource_name, raw_conf, resource_config, owner_list, re_list, configuration, fill_helpers) output_objects.append({ 'object_type': 'html_form', 'text': res_html }) # Pending requests target_op = "addresowner" csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) helper = html_post_helper( target_op, "%s.py" % target_op, { 'unique_resource_name': unique_resource_name, 'cert_id': '__DYNAMIC__', 'request_name': '__DYNAMIC__', csrf_field: csrf_token }) output_objects.append({ 'object_type': 'html_form', 'text': helper }) target_op = "rejectresreq" csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) helper = html_post_helper( target_op, "%s.py" % target_op, { 'unique_resource_name': unique_resource_name, 'request_name': '__DYNAMIC__', csrf_field: csrf_token }) output_objects.append({ 'object_type': 'html_form', 'text': helper }) request_dir = os.path.join(configuration.resource_home, unique_resource_name) request_list = [] for req_name in list_access_requests(configuration, request_dir): req = load_access_request(configuration, request_dir, req_name) if not req: continue if req.get('request_type', None) != "resourceowner": logger.error( "unexpected request_type %(request_type)s" % req) continue request_item = build_accessrequestitem_object( configuration, req) # Convert filename with exotic chars into url-friendly pure hex version shared_args = { "unique_resource_name": unique_resource_name, "request_name": hexlify(req["request_name"]) } accept_args, reject_args = {}, {} accept_args.update(shared_args) reject_args.update(shared_args) if req['request_type'] == "resourceowner": accept_args["cert_id"] = req["entity"] request_item['acceptrequestlink'] = { 'object_type': 'link', 'destination': "javascript: confirmDialog(%s, '%s', %s, %s);" % ("addresowner", "Accept %(target)s %(request_type)s request from %(entity)s" % req, 'undefined', "{%s}" % ', '.join([ "'%s': '%s'" % pair for pair in accept_args.items() ])), 'class': 'addlink iconspace', 'title': 'Accept %(target)s %(request_type)s request from %(entity)s' % req, 'text': '' } request_item['rejectrequestlink'] = { 'object_type': 'link', 'destination': "javascript: confirmDialog(%s, '%s', %s, %s);" % ("rejectresreq", "Reject %(target)s %(request_type)s request from %(entity)s" % req, 'undefined', "%s" % reject_args), 'class': 'removelink iconspace', 'title': 'Reject %(target)s %(request_type)s request from %(entity)s' % req, 'text': '' } request_list.append(request_item) output_objects.append({ 'object_type': 'sectionheader', 'text': "Pending Requests" }) output_objects.append({ 'object_type': 'table_pager', 'id_prefix': 'accessrequests_', 'entry_name': 'access requests', 'default_entries': default_pager_entries }) output_objects.append({ 'object_type': 'accessrequests', 'accessrequests': request_list }) output_objects.append({ 'object_type': 'sectionheader', 'text': 'Retire resource' }) output_objects.append({ 'object_type': 'text', 'text': ''' Use the link below to permanently remove the resource from the grid after stopping all units and the front end. ''' }) target_op = "delres" csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) js_name = 'delres%s' % hexlify(unique_resource_name) helper = html_post_helper( js_name, '%s.py' % target_op, { 'unique_resource_name': unique_resource_name, csrf_field: csrf_token }) output_objects.append({ 'object_type': 'html_form', 'text': helper }) output_objects.append({ 'object_type': 'link', 'destination': "javascript: confirmDialog(%s, '%s');" % (js_name, 'Really delete %s? (fails if it is busy)' % unique_resource_name), 'class': 'removelink iconspace', 'title': 'Delete %s' % unique_resource_name, 'text': 'Delete %s' % unique_resource_name }) owned += 1 if owned == 0: output_objects.append({ 'object_type': 'text', 'text': 'You are not listed as owner of any resources!' }) else: sorted_links = quick_res.items() sorted_links.sort() for (res_id, link_obj) in sorted_links: quick_links.append(link_obj) # add new line quick_links.append({'object_type': 'text', 'text': ''}) quick_links.append({ 'object_type': 'html_form', 'text': '</div><div class="quicklinks">' }) quick_links.append({ 'object_type': 'link', 'destination': "javascript:toggleHidden('.quicklinks');", 'class': 'additemlink iconspace', 'title': 'Toggle view', 'text': 'Show quick links' }) quick_links.append({'object_type': 'html_form', 'text': '</div>'}) output_objects = output_objects[:quick_links_index]\ + quick_links + output_objects[quick_links_index:] return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) status = returnvalues.OK defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Advanced Shell' if accepted['menu'][-1] == 'no': title_entry['skipmenu'] = True title_entry['skipwidgets'] = True title_entry['style'] = ''' <style type="text/css"> #content { margin: 10px } </style>''' # Please have href points to the CSS file and have basedir changed to the # directory where JavaScripts are placed. title_entry['style'] += ''' <link rel="stylesheet" type="text/css" href="/images/css/shell.css" media="screen"/> ''' title_entry['javascript'] = ''' <script type="text/javascript"> var basedir="/images/js/"; var shell; var interval; // scripts have to be loaded in sequence, thereby this recursion. var scripts=["toolkits.js","gui.js","ajax.js","intellisense.js", "output.js","status.js","lib.js","shell.js"]; function loadAll(s_i) { if(s_i<1) { shell=new Shell('shell', 'shell', 'xmlrpcinterface.py'); shell.Init(); return; } var script=document.createElement('script'); script.setAttribute('type','text/javascript'); script.setAttribute('src',basedir + scripts[ scripts.length - s_i ]); document.getElementsByTagName('head')[0].appendChild(script); if ( script.readyState ) { // IE style browser script.onreadystatechange= function () { if(this.readyState=='loaded'||this.readyState=='complete') loadAll( s_i-1 ); } } else { // other browser, should support onload script.onload=function() { loadAll( s_i-1 ); } } return; } </script> ''' # title_entry['bodyfunctions']='onload="mkShell();"' title_entry['bodyfunctions']='onload="loadAll(scripts.length);"' output_objects.append({'object_type': 'header', 'text': 'Advanced Shell' }) output_objects.append({'object_type': 'html_form', 'text' :'<div id="shell"><!-- filled by js --></div>'}) return (output_objects, status)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) output_objects.append({'object_type': 'header', 'text': '%s Request Virtual Machine' % \ configuration.short_title}) status = returnvalues.OK defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Virtual Machines' if not configuration.site_enable_vmachines: output_objects.append({'object_type': 'text', 'text': '''Virtual machines are disabled on this site. Please contact the Grid admins %s if you think they should be enabled. ''' % configuration.admin_email}) return (output_objects, returnvalues.OK) build_form = ''' <form method="post" action="vmachines.py"> <input type="hidden" name="output_format" value="html"> <input type="hidden" name="action" value="create"> <table style="margin: 0px; width: 100%;"> <tr> <td style="width: 20%;">Machine name</td> <td> <input type="text" name="machine_name" size="30" value="MyVirtualDesktop"> </td> </tr> </table> <fieldset> <legend><input type="radio" name="machine_type" value="pre" checked="checked">Prebuilt</legend> <table> <tr> <td style="width: 20%;">Choose a OS version</td> <td> <select name="os"> ''' for os in vms.available_os_list(configuration): build_form += '<option value="%s">%s</option>\n' % \ (os, os.capitalize()) build_form += ''' </select> </td> </tr> <tr> <td>Choose a machine image</td> <td> <select name="flavor"> ''' for flavor in vms.available_flavor_list(configuration): build_form += '<option value="%s">%s</option>\n' % \ (flavor, flavor.capitalize()) build_form += """ </select> </td> </tr> <tr> <td>Select a runtime environment providing the chosen OS and flavor combination. For Ubuntu systems you can typically just use a runtime env from the same year, like VBOX3.1-IMAGES-2010-1 for ubuntu-10.* versions.</td> <td> <input type="hidden" name="hypervisor_re" value="%s"> <select name="sys_re"> """ % configuration.vm_default_hypervisor_re for sys_re in vms.available_sys_re_list(configuration): build_form += '<option value="%s">%s</option>\n' % \ (sys_re, sys_re) build_form += ''' </select> </td> </tr> </table> </fieldset> <fieldset> <legend><input type="radio" name="machine_type" value="custom" disabled>Custom:</legend> <span class="warningtext">Custom builds are currently unavailable.</span> <table> <tr> <td style="width: 20%;">Software</td> <td> <input type=text size=80 name="machine_software" readonly value="iptables acpid x11vnc xorg gdm xfce4 gcc make netsurf python-openssl" /> </td> </tr> </table> </fieldset> <input type="submit" value="Submit machine request!"> </form> ''' output_objects.append({'object_type': 'html_form', 'text': build_form}) return (output_objects, status)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Resource details' output_objects.append({'object_type': 'header', 'text' : 'Show resource details'}) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) resource_list = accepted['unique_resource_name'] status = returnvalues.OK visible_res = user_visible_res_confs(configuration, client_id) vgrid_access = user_vgrid_access(configuration, client_id) res_map = get_resource_map(configuration) anon_map = anon_to_real_res_map(configuration.resource_home) for visible_res_name in resource_list: unique_resource_name = visible_res_name if visible_res_name in anon_map.keys(): unique_resource_name = anon_map[visible_res_name] if not visible_res_name in visible_res.keys(): logger.warning('User %s not allowed to view %s (%s)' % \ (client_id, visible_res_name, visible_res.keys())) output_objects.append({'object_type': 'error_text', 'text': 'invalid resource %s' % \ visible_res_name}) continue res_dict = visible_res[visible_res_name] res_item = build_resitem_object_from_res_dict(configuration, visible_res_name, res_dict, vgrid_access) output_objects.append(res_item) if client_id in res_map[unique_resource_name][OWNERS]: output_objects.append({'object_type': 'sectionheader', 'text': 'Administrate'}) output_objects.append({'object_type': 'link', 'destination': 'resadmin.py?unique_resource_name=%s'\ % unique_resource_name, 'class': 'adminlink iconspace', 'title': 'Administrate %s' % unique_resource_name, 'text': 'Administrate %s' % unique_resource_name, }) return (output_objects, status)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) vgrid_name = accepted['vgrid_name'][-1] # prepare support for confirm dialog and toggling the views (by css/jquery) title_entry = find_entry(output_objects, 'title') title_entry['text'] = "Administrate %s: %s" % \ (configuration.site_vgrid_label, vgrid_name) title_entry['style'] = themed_styles(configuration) title_entry['javascript'] = ''' <script type="text/javascript" src="/images/js/jquery.js"></script> <script type="text/javascript" src="/images/js/jquery-ui.js"></script> <script type="text/javascript" src="/images/js/jquery.confirm.js"></script> <script type="text/javascript" > var toggleHidden = function(classname) { // classname supposed to have a leading dot $(classname).toggleClass('hidden'); } $(document).ready(function() { // init confirmation dialog $( "#confirm_dialog" ).dialog( // see http://jqueryui.com/docs/dialog/ for options { autoOpen: false, modal: true, closeOnEscape: true, width: 500, buttons: { "Cancel": function() { $( "#" + name ).dialog("close"); } } }); } ); </script> ''' output_objects.append({'object_type': 'html_form', 'text':''' <div id="confirm_dialog" title="Confirm" style="background:#fff;"> <div id="confirm_text"><!-- filled by js --></div> <textarea cols="40" rows="4" id="confirm_input" style="display:none;"></textarea> </div> ''' }) output_objects.append({'object_type': 'header', 'text' : "Administrate '%s'" % vgrid_name }) if not vgrid_is_owner(vgrid_name, client_id, configuration): output_objects.append({'object_type': 'error_text', 'text': 'Only owners of %s can administrate it.' % vgrid_name }) js_name = 'reqvgridowner%s' % hexlify(vgrid_name) helper = html_post_helper(js_name, 'sendrequestaction.py', {'vgrid_name': vgrid_name, 'request_type': 'vgridowner', 'request_text': ''}) output_objects.append({'object_type': 'html_form', 'text': helper}) output_objects.append( {'object_type': 'link', 'destination': "javascript: confirmDialog(%s, '%s', '%s');"\ % (js_name, "Request ownership of " + \ vgrid_name + ":<br/>" + \ "\nPlease write a message to the owners below.", 'request_text'), 'class': 'addadminlink', 'title': 'Request ownership of %s' % vgrid_name, 'text': 'Apply to become an owner'}) return (output_objects, returnvalues.SYSTEM_ERROR) for (item, scr) in zip(['owner', 'member', 'resource'], ['vgridowner', 'vgridmember', 'vgridres']): output_objects.append({'object_type': 'sectionheader', 'text': "%ss" % item.title() }) if item == 'trigger': # Always run as rule creator to avoid users being able to act on # behalf of ANY other user using triggers (=exploit) extra_fields = [('path', None), ('changes', [keyword_all] + valid_trigger_changes), ('run_as', client_id), ('action', [keyword_auto] + valid_trigger_actions), ('arguments', None)] else: extra_fields = [] (status, oobjs) = vgrid_add_remove_table(client_id, vgrid_name, item, scr, configuration, extra_fields) if not status: output_objects.extend(oobjs) return (output_objects, returnvalues.SYSTEM_ERROR) else: output_objects.append({'object_type': 'html_form', 'text': '<div class="div-%s">' % item }) output_objects.append( {'object_type': 'link', 'destination': "javascript:toggleHidden('.div-%s');" % item, 'class': 'removeitemlink', 'title': 'Toggle view', 'text': 'Hide %ss' % item.title() }) output_objects.extend(oobjs) output_objects.append( {'object_type': 'html_form', 'text': '</div><div class="hidden div-%s">' % item}) output_objects.append( {'object_type': 'link', 'destination': "javascript:toggleHidden('.div-%s');" % item, 'class': 'additemlink', 'title': 'Toggle view', 'text': 'Show %ss' % item.title() }) output_objects.append({'object_type': 'html_form', 'text': '</div>' }) # Checking/fixing of missing components output_objects.append({'object_type': 'sectionheader', 'text': "Repair/Add Components"}) output_objects.append({'object_type': 'html_form', 'text': ''' <form method="post" action="updatevgrid.py"> <input type="hidden" name="vgrid_name" value="%(vgrid)s" /> <input type="submit" value="Repair components" /> </form> ''' % {'vgrid': vgrid_name}}) output_objects.append({'object_type': 'sectionheader', 'text': "Delete %s " % vgrid_name}) output_objects.append({'object_type': 'html_form', 'text': ''' To delete <b>%(vgrid)s</b> remove all members and owners ending with yourself. ''' % {'vgrid': vgrid_name}}) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Delete runtime environment' output_objects.append({ 'object_type': 'header', 'text': 'Delete runtime environment' }) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) re_name = accepted['re_name'][-1] if not safe_handler(configuration, 'post', op_name, client_id, get_csrf_limit(configuration), accepted): output_objects.append({ 'object_type': 'error_text', 'text': '''Only accepting CSRF-filtered POST requests to prevent unintended updates''' }) return (output_objects, returnvalues.CLIENT_ERROR) if not valid_dir_input(configuration.re_home, re_name): logger.warning( "possible illegal directory traversal attempt re_name '%s'" % re_name) output_objects.append({ 'object_type': 'error_text', 'text': 'Illegal runtime environment name: "%s"' % re_name }) return (output_objects, returnvalues.CLIENT_ERROR) # Check whether re_name represents a runtime environment if not is_runtime_environment(re_name, configuration): output_objects.append({ 'object_type': 'error_text', 'text': "No such runtime environment: '%s'" % re_name }) return (output_objects, returnvalues.CLIENT_ERROR) (re_dict, load_msg) = get_re_dict(re_name, configuration) if not re_dict: output_objects.append({ 'object_type': 'error_text', 'text': 'Could not read runtime environment details for %s: %s' % (re_name, load_msg) }) return (output_objects, returnvalues.SYSTEM_ERROR) # Make sure the runtime environment belongs to the user trying to delete it if client_id != re_dict['CREATOR']: output_objects.append({'object_type': 'error_text', 'text': \ 'You are not the owner of runtime environment "%s"' % re_name}) return (output_objects, returnvalues.CLIENT_ERROR) # Prevent delete if the runtime environment is used by any resources actives = resources_using_re(configuration, re_name) # If the runtime environment is active, an error message is printed, along # with a list of the resources using the runtime environment if actives: output_objects.append({ 'object_type': 'error_text', 'text': "Can't delete runtime environment '%s' in use by resources:" % re_name }) output_objects.append({'object_type': 'list', 'list': actives}) output_objects.append({ 'object_type': 'link', 'destination': 'redb.py', 'class': 'infolink iconspace', 'title': 'Show runtime environments', 'text': 'Show runtime environments' }) return (output_objects, returnvalues.CLIENT_ERROR) # Delete the runtime environment (del_status, msg) = delete_runtimeenv(re_name, configuration) # If something goes wrong when trying to delete runtime environment # re_name, an error is displayed. if not del_status: output_objects.append({ 'object_type': 'error_text', 'text': 'Could not remove %s runtime environment: %s' % (re_name, msg) }) return (output_objects, returnvalues.SYSTEM_ERROR) # If deletion of runtime environment re_name is successful, we just # return OK else: output_objects.append({ 'object_type': 'text', 'text': 'Successfully deleted runtime environment: "%s"' % re_name }) output_objects.append({ 'object_type': 'link', 'destination': 'redb.py', 'class': 'infolink iconspace', 'title': 'Show runtime environments', 'text': 'Show runtime environments' }) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) status = returnvalues.OK defaults = signature()[1] title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Resource management' (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) show_sandboxes = (accepted['show_sandboxes'][-1] != 'false') operation = accepted['operation'][-1] caching = (accepted['caching'][-1].lower() in ('true', 'yes')) if not configuration.site_enable_resources: output_objects.append({ 'object_type': 'error_text', 'text': '''Resources are not enabled on this system''' }) return (output_objects, returnvalues.SYSTEM_ERROR) if not operation in allowed_operations: output_objects.append({ 'object_type': 'text', 'text': '''Operation must be one of %s.''' % ', '.join(allowed_operations) }) return (output_objects, returnvalues.OK) logger.info("%s %s begin for %s" % (op_name, operation, client_id)) pending_updates = False if operation in show_operations: # jquery support for tablesorter and confirmation on delete # table initially sorted by col. 1 (admin), then 0 (name) # NOTE: We distinguish between caching on page load and forced refresh refresh_call = 'ajax_resman(%s)' table_spec = { 'table_id': 'resourcetable', 'sort_order': '[[1,0],[0,0]]', 'refresh_call': refresh_call % 'false' } (add_import, add_init, add_ready) = man_base_js(configuration, [table_spec]) if operation == "show": add_ready += '%s;' % refresh_call % 'true' title_entry['script']['advanced'] += add_import title_entry['script']['init'] += add_init title_entry['script']['ready'] += add_ready output_objects.append({ 'object_type': 'html_form', 'text': man_base_html(configuration) }) output_objects.append({ 'object_type': 'header', 'text': 'Available Resources' }) output_objects.append({ 'object_type': 'sectionheader', 'text': 'Resources available on this server' }) output_objects.append({ 'object_type': 'text', 'text': ''' All available resources are listed below with overall hardware specifications. Any resources that you own will have a administration icon that you can click to open resource management. ''' }) # Helper forms for requests and removes form_method = 'post' csrf_limit = get_csrf_limit(configuration) target_op = 'sendrequestaction' csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) helper = html_post_helper( 'reqresowner', '%s.py' % target_op, { 'unique_resource_name': '__DYNAMIC__', 'request_type': 'resourceowner', 'request_text': '', csrf_field: csrf_token }) output_objects.append({'object_type': 'html_form', 'text': helper}) target_op = 'rmresowner' csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) helper = html_post_helper( 'rmresowner', '%s.py' % target_op, { 'unique_resource_name': '__DYNAMIC__', 'cert_id': client_id, csrf_field: csrf_token }) output_objects.append({'object_type': 'html_form', 'text': helper}) output_objects.append({ 'object_type': 'table_pager', 'entry_name': 'resources', 'default_entries': default_pager_entries }) resources = [] if operation in list_operations: logger.info("get vgrid and resource map with caching %s" % caching) visible_res_confs = user_visible_res_confs(configuration, client_id, caching) res_map = get_resource_map(configuration, caching) anon_map = anon_to_real_res_map(configuration.resource_home) if caching: modified_resources, _ = check_resources_modified(configuration) modified_vgrids, _ = check_vgrids_modified(configuration) if modified_resources: logger.info("pending resource cache updates: %s" % modified_resources) pending_updates = True elif modified_vgrids: logger.info("pending vgrid cache updates: %s" % modified_vgrids) pending_updates = True else: logger.info("no pending cache updates") # Iterate through resources and show management for each one requested fields = [ 'PUBLICNAME', 'NODECOUNT', 'CPUCOUNT', 'MEMORY', 'DISK', 'ARCHITECTURE', 'SANDBOX', 'RUNTIMEENVIRONMENT' ] # NOTE: only resources that user is allowed to access are listed. # Resource with neither exes nor stores are not shown to anyone # but the owners. Similarly resources are not shown if all # resource units solely participate in VGrids, which the user # can't access. for visible_res_name in visible_res_confs.keys(): unique_resource_name = visible_res_name if visible_res_name in anon_map.keys(): unique_resource_name = anon_map[visible_res_name] if not show_sandboxes and sandbox_resource(unique_resource_name): continue res_obj = {'object_type': 'resource', 'name': visible_res_name} if client_id in res_map[unique_resource_name][OWNERS]: # Admin of resource when owner res_obj['resownerlink'] = { 'object_type': 'link', 'destination': "javascript: confirmDialog(%s, '%s', %s, %s);" % ('rmresowner', 'Really leave %s owners?' % unique_resource_name, 'undefined', "{unique_resource_name: '%s'}" % unique_resource_name), 'class': 'removelink iconspace', 'title': 'Leave %s owners' % unique_resource_name, 'text': '' } res_obj['resdetailslink'] = { 'object_type': 'link', 'destination': 'resadmin.py?unique_resource_name=%s' % unique_resource_name, 'class': 'adminlink iconspace', 'title': 'Administrate %s' % unique_resource_name, 'text': '' } else: # link to become owner res_obj['resownerlink'] = { 'object_type': 'link', 'destination': "javascript: confirmDialog(%s, '%s', '%s', %s);" % ('reqresowner', "Request ownership of " + visible_res_name + ":<br/>" + "\nPlease write a message to the owners (field below).", 'request_text', "{unique_resource_name: '%s'}" % visible_res_name), 'class': 'addlink iconspace', 'title': 'Request ownership of %s' % visible_res_name, 'text': '' } res_obj['resdetailslink'] = { 'object_type': 'link', 'destination': 'viewres.py?unique_resource_name=%s' % visible_res_name, 'class': 'infolink iconspace', 'title': 'View detailed %s specs' % visible_res_name, 'text': '' } # fields for everyone: public status for name in fields: res_obj[name] = res_map[unique_resource_name][CONF].get( name, '') # Use runtimeenvironment names instead of actual definitions res_obj['RUNTIMEENVIRONMENT'] = [ i[0] for i in res_obj['RUNTIMEENVIRONMENT'] ] res_obj['RUNTIMEENVIRONMENT'].sort() resources.append(res_obj) if operation == "show": # insert dummy placeholder to build table res_obj = {'object_type': 'resource', 'name': ''} resources.append(res_obj) output_objects.append({ 'object_type': 'resource_list', 'pending_updates': pending_updates, 'resources': resources }) if operation in show_operations: if configuration.site_enable_sandboxes: if show_sandboxes: output_objects.append({ 'object_type': 'link', 'destination': '?show_sandboxes=false', 'class': 'removeitemlink iconspace', 'title': 'Hide sandbox resources', 'text': 'Exclude sandbox resources', }) else: output_objects.append({ 'object_type': 'link', 'destination': '?show_sandboxes=true', 'class': 'additemlink iconspace', 'title': 'Show sandbox resources', 'text': 'Include sandbox resources', }) output_objects.append({ 'object_type': 'sectionheader', 'text': 'Resource Status' }) output_objects.append({ 'object_type': 'text', 'text': ''' Live resource status is available in the resource monitor page with all %s/resources you can access ''' % configuration.site_vgrid_label }) output_objects.append({ 'object_type': 'link', 'destination': 'showvgridmonitor.py?vgrid_name=ALL', 'class': 'monitorlink iconspace', 'title': 'Show monitor with all resources you can access', 'text': 'Global resource monitor', }) output_objects.append({ 'object_type': 'sectionheader', 'text': 'Additional Resources' }) output_objects.append({ 'object_type': 'text', 'text': 'You can sign up spare or dedicated resources to the grid below.' }) output_objects.append({ 'object_type': 'link', 'destination': 'resedit.py', 'class': 'addlink iconspace', 'title': 'Show sandbox resources', 'text': 'Create a new %s resource' % configuration.short_title, }) output_objects.append({'object_type': 'sectionheader', 'text': ''}) if configuration.site_enable_sandboxes: output_objects.append({ 'object_type': 'link', 'destination': 'ssslogin.py', 'class': 'adminlink iconspace', 'title': 'Administrate and monitor your sandbox resources', 'text': 'Administrate %s sandbox resources' % configuration.short_title }) output_objects.append({'object_type': 'sectionheader', 'text': ''}) output_objects.append({ 'object_type': 'link', 'destination': 'oneclick.py', 'class': 'sandboxlink iconspace', 'title': 'Run a One-click resource in your browser', 'text': 'Use this computer as One-click %s resource' % configuration.short_title }) logger.info("%s %s end for %s" % (op_name, operation, client_id)) return (output_objects, status)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False, op_menu=False) defaults = signature()[1] (validate_status, accepted) = validate_input(user_arguments_dict, defaults, output_objects, allow_rejects=False) if not validate_status: logger.warning('%s invalid input: %s' % (op_name, accepted)) return (accepted, returnvalues.CLIENT_ERROR) if not 'migcert' in configuration.site_signup_methods: output_objects.append({ 'object_type': 'error_text', 'text': '''X.509 certificate login is not enabled on this site''' }) return (output_objects, returnvalues.SYSTEM_ERROR) title_entry = find_entry(output_objects, 'title') title_entry['text'] = '%s certificate account request' % \ configuration.short_title title_entry['skipmenu'] = True output_objects.append({ 'object_type': 'header', 'text': '%s certificate account request' % configuration.short_title }) admin_email = configuration.admin_email smtp_server = configuration.smtp_server user_pending = os.path.abspath(configuration.user_pending) # force name to capitalized form (henrik karlsen -> Henrik Karlsen) # please note that we get utf8 coded bytes here and title() treats such # chars as word termination. Temporarily force to unicode. raw_name = accepted['cert_name'][-1].strip() try: cert_name = force_utf8(force_unicode(raw_name).title()) except Exception: cert_name = raw_name.title() country = accepted['country'][-1].strip().upper() state = accepted['state'][-1].strip().title() org = accepted['org'][-1].strip() # lower case email address email = accepted['email'][-1].strip().lower() password = accepted['password'][-1] verifypassword = accepted['verifypassword'][-1] # keep comment to a single line comment = accepted['comment'][-1].replace('\n', ' ') # single quotes break command line format - remove comment = comment.replace("'", ' ') if not safe_handler(configuration, 'post', op_name, client_id, get_csrf_limit(configuration), accepted): output_objects.append({ 'object_type': 'error_text', 'text': '''Only accepting CSRF-filtered POST requests to prevent unintended updates''' }) return (output_objects, returnvalues.CLIENT_ERROR) if password != verifypassword: output_objects.append({ 'object_type': 'error_text', 'text': 'Password and verify password are not identical!' }) return (output_objects, returnvalues.CLIENT_ERROR) try: assure_password_strength(configuration, password) except Exception, exc: logger.warning( "%s invalid password for '%s' (policy %s): %s" % (op_name, cert_name, configuration.site_password_policy, exc)) output_objects.append({ 'object_type': 'error_text', 'text': 'Invalid password requested: %s.' % exc }) output_objects.append({ 'object_type': 'link', 'destination': 'javascript:history.back();', 'class': 'genericbutton', 'text': "Try again" }) return (output_objects, returnvalues.CLIENT_ERROR)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) flavor = accepted['flavor'][-1].strip() if not flavor in freeze_flavors.keys(): output_objects.append({'object_type': 'error_text', 'text': 'Invalid freeze flavor: %s' % flavor}) return (output_objects, returnvalues.CLIENT_ERROR) title = freeze_flavors[flavor]['adminfreeze_title'] output_objects.append({'object_type': 'header', 'text': title}) title_entry = find_entry(output_objects, 'title') title_entry['text'] = title if not configuration.site_enable_freeze: output_objects.append({'object_type': 'text', 'text': '''Freezing archives is disabled on this site. Please contact the Grid admins %s if you think it should be enabled. ''' % configuration.admin_email}) return (output_objects, returnvalues.OK) # jquery support for dynamic addition of copy/upload fields title_entry['style'] = themed_styles(configuration, base=['jquery.contextmenu.css', 'jquery.xbreadcrumbs.css', 'jquery.fmbreadcrumbs.css', 'jquery.fileupload.css', 'jquery.fileupload-ui.css'], skin=['fileupload-ui.custom.css', 'xbreadcrumbs.custom.css']) title_entry['javascript'] = ''' <script type="text/javascript" src="/images/js/jquery.js"></script> <script type="text/javascript" src="/images/js/jquery-ui.js"></script> <!-- Filemanager and dependencies --> <script type="text/javascript" src="/images/js/jquery.form.js"></script> <script type="text/javascript" src="/images/js/jquery.prettyprint.js"></script> <script type="text/javascript" src="/images/js/jquery.filemanager.js"></script> <script type="text/javascript" src="/images/js/jquery.tablesorter.js"></script> <script type="text/javascript" src="/images/js/jquery.tablesorter.pager.js"></script> <script type="text/javascript" src="/images/js/jquery.tablesorter.widgets.js"></script> <script type="text/javascript" src="/images/js/jquery.contextmenu.js"></script> <script type="text/javascript" src="/images/js/jquery.xbreadcrumbs.js"></script> <!-- The preview image plugin --> <script type="text/javascript" src="/images/js/preview.js"></script> <!-- The image manipulation CamanJS plugin used by the preview image plugin --> <script type="text/javascript" src="/images/lib/CamanJS/dist/caman.full.js"></script> <script type="text/javascript"> Caman.DEBUG = false </script> <!-- The nouislider plugin used by the preview image plugin --> <script type="text/javascript" src="/images/lib/noUiSlider/jquery.nouislider.all.js"></script> <!-- Fancy file uploader and dependencies --> <!-- The Templates plugin is included to render the upload/download listings --> <script type="text/javascript" src="/images/js/tmpl.min.js"></script> <!-- The Load Image plugin is included for the preview images and image resizing functionality --> <script type="text/javascript" src="/images/js/load-image.min.js"></script> <!-- Bootstrap JS is not required, but included for the responsive demo navigation --> <!-- The Iframe Transport is required for browsers without support for XHR file uploads --> <script type="text/javascript" src="/images/js/jquery.iframe-transport.js"></script> <!-- The basic File Upload plugin --> <script type="text/javascript" src="/images/js/jquery.fileupload.js"></script> <!-- The File Upload processing plugin --> <script type="text/javascript" src="/images/js/jquery.fileupload-process.js"></script> <!-- The File Upload image preview & resize plugin --> <script type="text/javascript" src="/images/js/jquery.fileupload-image.js"></script> <!-- The File Upload validation plugin --> <script type="text/javascript" src="/images/js/jquery.fileupload-validate.js"></script> <!-- The File Upload user interface plugin --> <script type="text/javascript" src="/images/js/jquery.fileupload-ui.js"></script> <!-- The File Upload jQuery UI plugin --> <script type="text/javascript" src="/images/js/jquery.fileupload-jquery-ui.js"></script> <!-- The template to display files available for upload --> <script id="template-upload" type="text/x-tmpl"> {% console.log("using upload template"); %} {% console.log("... with upload files: "+$.fn.dump(o)); %} {% var dest_dir = "./" + $("#fancyfileuploaddest").val(); %} {% console.log("using upload dest: "+dest_dir); %} {% for (var i=0, file; file=o.files[i]; i++) { %} {% var rel_path = $.fn.normalizePath(dest_dir+"/"+file.name); %} {% console.log("using upload rel_path: "+rel_path); %} <tr class="template-upload fade"> <td> <span class="preview"></span> </td> <td> <p class="name">{%=rel_path%}</p> <strong class="error"></strong> </td> <td> <div class="size pending">Processing...</div> <div class="progress"></div> </td> <td> {% if (!i && !o.options.autoUpload) { %} <button class="start" disabled>Start</button> {% } %} {% if (!i) { %} <button class="cancel">Cancel</button> {% } %} </td> </tr> {% } %} </script> <!-- The template to display files available for download --> <script id="template-download" type="text/x-tmpl"> {% console.log("using download template"); %} {% console.log("... with download files: "+$.fn.dump(o)); %} {% for (var i=0, file; file=o.files[i]; i++) { %} {% var rel_path = $.fn.normalizePath("./"+file.name); %} {% console.log("using download rel_path: "+rel_path); %} <tr class="template-download fade"> <td> <span class="preview"> {% if (file.thumbnailUrl) { %} <a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" data-gallery><img src="{%=file.thumbnailUrl%}"></a> {% } %} </span> </td> <td> <p class="name"> <a href="{%=file.url%}" title="{%=file.name%}" download="{%=file.name%}" {%=file.thumbnailUrl?\'data-gallery\':\'\'%}>{%=rel_path%}</a> </p> {% if (file.error) { %} <div><span class="error">Error</span> {%=file.error%}</div> {% } %} </td> <td> <div class="size">{%=o.formatFileSize(file.size)%}</div> </td> <td> <button class="delete" data-type="{%=file.deleteType%}" data-url="{%=file.deleteUrl%}"{% if (file.deleteWithCredentials) { %} data-xhr-fields=\'{"withCredentials":true}\'{% } %}>{% if (file.deleteUrl) { %}Delete{% } else { %}Dismiss{% } %}</button> <input type="checkbox" name="delete" value="1" class="toggle"> </td> </tr> {% } %} </script> <script type="text/javascript" > var copy_fields = 0; var upload_fields = 0; var open_file_chooser; var open_upload_dialog; ''' title_entry['javascript'] += ''' /* default upload destination */ var remote_path = "%s"; ''' % upload_tmp_dir title_entry['javascript'] += ''' function add_copy(div_id) { var field_id = "freeze_copy_"+copy_fields; var field_name = "freeze_copy_"+copy_fields; var wrap_id = field_id+"_wrap"; var browse_id = field_id+"_browse"; copy_entry = "<span id=\'"+wrap_id+"\'>"; copy_entry += "<input type=\'button\' value=\'Remove\' "; copy_entry += " onClick=\'remove_field(\"+wrap_id+\");\'/>"; // add browse button to mimic upload field copy_entry += "<input type=\'button\' id=\'"+browse_id+"\' "; copy_entry += " value=\'Browse...\' />"; copy_entry += "<input type=\'text\' id=\'"+field_id+"\' "; copy_entry += " name=\'" + field_name + "\' size=80 /><br / >"; copy_entry += "</span>"; $("#"+div_id).append(copy_entry); $("#"+field_id).click(function() { open_file_chooser("Add file or directory (right click to select)", function(file) { $("#"+field_id).val(file); }); }); $("#"+browse_id).click(function() { $("#"+field_id).click(); }); $("#"+field_id).click(); copy_fields += 1; } function add_upload(div_id) { var field_id, field_name, wrap_id, path, on_remove; open_upload_dialog("Upload Files", function() { console.log("in upload callback"); $(".uploadfileslist > tr > td > p.name > a").each( function(index) { console.log("callback for upload item no. "+index); path = $(this).text(); if ($(this).attr("href") == "") { console.log("skipping empty (error) upload: "+path); // Continue to next iteration on errors return true; } console.log("callback for upload path "+path); field_id = "freeze_move_"+upload_fields; field_name = "freeze_move_"+upload_fields; wrap_id = field_id+"_wrap"; if ($("#"+div_id+" > span > input[value=\'"+path+"\']").length) { console.log("skipping duplicate path: "+path); // Continue to next iteration on errors return true; } else { console.log("adding new path: "+path); } on_remove = ""; on_remove += "remove_field("+wrap_id+");"; on_remove += "$.fn.delete_upload(\\""+path+"\\");"; upload_entry = "<span id=\'"+wrap_id+"\'>"; upload_entry += "<input type=\'button\' value=\'Remove\' "; upload_entry += " onClick=\'"+on_remove+"\'/>"; upload_entry += "<input type=\'text\' id=\'"+field_id+"\' "; upload_entry += " name=\'" + field_name + "\' size=50 "; upload_entry += "value=\'"+path+"\' /><br / >"; upload_entry += "</span>"; $("#"+div_id).append(upload_entry); console.log("callback added upload: "+upload_entry); upload_fields += 1; }); console.log("callback done"); }, remote_path, true); } function remove_field(field_id) { $(field_id).remove(); } // init file chooser dialogs with directory selction support function init_dialogs() { open_file_chooser = mig_filechooser_init("fm_filechooser", function(file) { return; }, false, "/"); open_upload_dialog = mig_fancyuploadchunked_init("fancyuploadchunked_dialog"); $("#addfilebutton").click(function() { add_copy(\"copyfiles\"); }); $("#adduploadbutton").click(function() { add_upload(\"uploadfiles\"); }); } function init_page() { init_dialogs(); } $(document).ready(function() { // do sequenced initialisation (separate function) init_page(); } ); </script> ''' shared_files_form = """ <!-- and now this... we do not want to see it, except in a dialog: --> <div id='fm_filechooser' style='display:none'> <div class='fm_path_breadcrumbs'> <ul id='fm_xbreadcrumbs' class='xbreadcrumbs'> </ul> </div> <div class='fm_addressbar'> <input type='hidden' value='/' name='fm_current_path' /> </div> <div class='fm_folders'> <ul class='jqueryFileTree'> <li class='directory expanded'> <a>...</a> </li> </ul> </div> <div class='fm_files'> <table id='fm_filelisting' style='font-size:13px; border-spacing=0;'> <thead> <tr> <th>Name</th> <th style='width: 80px;'>Size</th> <th style='width: 50px;'>Type</th> <th style='width: 120px;'>Date Modified</th> </tr> </thead> <tbody> <!-- this is a placeholder for contents: do not remove! --> </tbody> </table> </div> <div id='fm_statusbar'> <div id='fm_statusprogress'><div class='progress-label'>Loading...</div></div> <div id='fm_statusinfo'> </div> </div> <div id='fm_options'><input id='fm_touchscreen' type='checkbox'> Enable touch screen interface (all clicks trigger menu) <input id='fm_dotfiles' type='checkbox'> Show hidden files and dirs </div> </div> <div id='cmd_dialog' title='Command output' style='display: none;'></div> <div id='fancyuploadchunked_dialog' title='Upload File' style='display: none;'> <!-- The file upload form used as target for the file upload widget --> <form id='fancyfileupload' action='uploadchunked.py?output_format=json;action=put' method='POST' enctype='multipart/form-data'> <fieldset id='fancyfileuploaddestbox'> <label id='fancyfileuploaddestlabel' for='fancyfileuploaddest'> Optional final destination dir: </label> <input id='fancyfileuploaddest' type='text' size=60 value=''> </fieldset> <!-- The fileupload-buttonbar contains buttons to add/delete files and start/cancel the upload --> <div class='fileupload-buttonbar'> <div class='fileupload-buttons'> <!-- The fileinput-button span is used to style the file input field as button --> <span class='fileinput-button'> <span>Add files...</span> <input type='file' name='files[]' multiple> </span> <button type='submit' class='start'>Start upload</button> <button type='reset' class='cancel'>Cancel upload</button> <button type='button' class='delete'>Delete</button> <input type='checkbox' class='toggle'> <!-- The global file processing state --> <span class='fileupload-process'></span> </div> <!-- The global progress state --> <div class='fileupload-progress fade' style='display:none'> <!-- The global progress bar --> <div class='progress' role='progressbar' aria-valuemin='0' aria-valuemax='100'></div> <!-- The extended global progress state --> <div class='progress-extended'> </div> </div> </div> <!-- The table listing the files available for upload/download --> <table role='presentation' class='table table-striped'><tbody class='uploadfileslist'></tbody></table> </form> <!-- For status and error output messages --> <div id='fancyuploadchunked_output'></div> </div> """ if flavor == 'freeze': intro_text = """ Please enter your archive details below and select any files to be included in the archive. <p class='warn_message'>Note that a frozen archive can not be changed after creation and it can only be manually removed by the management, so please be careful when filling in the details. </p> """ files_form = shared_files_form freeze_form = """ <form enctype='multipart/form-data' method='post' action='createfreeze.py'> <b>Name:</b><br /> <input type='hidden' name='flavor' value='freeze' /> <input type='text' name='freeze_name' size=30 autofocus /> <input type='hidden' name='freeze_author' value='UNSET' /> <input type='hidden' name='freeze_department' value='UNSET' /> <input type='hidden' name='freeze_organization' value='UNSET' /> <br /><b>Description:</b><br /> <textarea cols='80' rows='20' name='freeze_description'></textarea> <br /> <br /> <div id='freezefiles'> <b>Freeze Archive Files:</b> <input type='button' id='addfilebutton' value='Add file/directory' /> <input type='button' id='adduploadbutton' value='Add upload' /> <div id='copyfiles'> <!-- Dynamically filled --> </div> <div id='uploadfiles'> <!-- Dynamically filled --> </div> </div> <br /> <div id='freezepublish'> <input type='checkbox' name='freeze_publish' /> <b>Make Dataset Publicly Available</b> </div> <br /> <input type='submit' value='Create Archive' /> </form> """ if flavor == 'phd': intro_text = """ Please enter your PhD details below and select any files associated with your thesis. <p class='warn_message'>Note that a thesis archive can not be changed after creation and it can only be manually removed by the management, so please be careful when filling in the details. </p> """ files_form = shared_files_form freeze_form = """ <form enctype='multipart/form-data' method='post' action='createfreeze.py'> <b>Thesis Title:</b><br /> <input type='hidden' name='flavor' value='phd' /> <input type='hidden' name='freeze_organization' value='UNSET' /> <input type='text' name='freeze_name' size=80 /> <br /><b>Author Name:</b><br /> <input type='text' name='freeze_author' size=40 /> <br /><b>Department:</b><br /> <input type='text' name='freeze_department' size=40 /> <br /> <br /> <div id='freezefiles'> <b>Thesis and Associated Files to Archive:</b> <input type='button' id='addfilebutton' value='Add file/directory' /> <input type='button' id='adduploadbutton' value='Add upload' /> <div id='copyfiles'> <!-- Dynamically filled --> </div> <div id='uploadfiles'> <!-- Dynamically filled --> </div> </div> <br /> <div id='freezepublish'> <input type='checkbox' name='freeze_publish' /> <b>Make Dataset Publicly Available</b> </div> <br /><b>Dataset Description:</b><br /> <textarea cols='80' rows='20' name='freeze_description'></textarea> <br /> <br /> <input type='submit' value='Archive Thesis' /> </form> """ output_objects.append({'object_type': 'html_form', 'text': intro_text}) output_objects.append({'object_type': 'html_form', 'text': files_form}) output_objects.append({'object_type': 'html_form', 'text': freeze_form}) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'People' (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) operation = accepted['operation'][-1] caching = (accepted['caching'][-1].lower() in ('true', 'yes')) if not operation in allowed_operations: output_objects.append({'object_type': 'text', 'text': '''Operation must be one of %s.''' % ', '.join(allowed_operations)}) return (output_objects, returnvalues.OK) logger.info("%s %s begin for %s" % (op_name, operation, client_id)) pending_updates = False if operation in show_operations: # jquery support for tablesorter and confirmation on "send" # table initially sorted by 0 (name) # NOTE: We distinguish between caching on page load and forced refresh refresh_helper = 'ajax_people(%s, %%s)' refresh_call = refresh_helper % configuration.notify_protocols table_spec = {'table_id': 'usertable', 'sort_order': '[[0,0]]', 'refresh_call': refresh_call % 'false'} (add_import, add_init, add_ready) = man_base_js(configuration, [table_spec], {'width': 640}) if operation == "show": add_ready += '%s;' % (refresh_call % 'true') title_entry['script']['advanced'] += add_import title_entry['script']['init'] += add_init title_entry['script']['ready'] += add_ready output_objects.append({'object_type': 'html_form', 'text': man_base_html(configuration)}) output_objects.append({'object_type': 'header', 'text': 'People'}) output_objects.append( {'object_type': 'text', 'text': 'View and communicate with other users.' }) output_objects.append( {'object_type': 'sectionheader', 'text': 'All users'}) # Helper form for sends form_method = 'post' csrf_limit = get_csrf_limit(configuration) target_op = 'sendrequestaction' csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) helper = html_post_helper('sendmsg', '%s.py' % target_op, {'cert_id': '__DYNAMIC__', 'protocol': '__DYNAMIC__', 'request_type': 'plain', 'request_text': '', csrf_field: csrf_token}) output_objects.append({'object_type': 'html_form', 'text': helper}) output_objects.append({'object_type': 'table_pager', 'entry_name': 'people', 'default_entries': default_pager_entries}) users = [] if operation in list_operations: logger.info("get vgrid and user map with caching %s" % caching) visible_user = user_visible_user_confs(configuration, client_id, caching) vgrid_access = user_vgrid_access(configuration, client_id, caching=caching) anon_map = anon_to_real_user_map(configuration) if not visible_user: output_objects.append( {'object_type': 'error_text', 'text': 'no users found!'}) return (output_objects, returnvalues.SYSTEM_ERROR) if caching: modified_users, _ = check_users_modified(configuration) modified_vgrids, _ = check_vgrids_modified(configuration) if modified_users: logger.info("pending user cache updates: %s" % modified_users) pending_updates = True elif modified_vgrids: logger.info("pending vgrid cache updates: %s" % modified_vgrids) pending_updates = True else: logger.info("no pending cache updates") for (visible_user_id, user_dict) in visible_user.items(): user_id = visible_user_id if visible_user_id in anon_map.keys(): # Maintain user anonymity pretty_id = 'Anonymous user with unique ID %s' % visible_user_id user_id = anon_map[visible_user_id] else: # Show user-friendly version of user ID hide_email = user_dict.get(CONF, {}).get('HIDE_EMAIL_ADDRESS', True) pretty_id = pretty_format_user(user_id, hide_email) user_obj = {'object_type': 'user', 'name': visible_user_id, 'pretty_id': pretty_id} user_obj.update(user_dict) # NOTE: datetime is not json-serializable so we force to string created = user_obj.get(CONF, {}).get('CREATED_TIMESTAMP', '') if created: user_obj[CONF]['CREATED_TIMESTAMP'] = str(created) user_obj['userdetailslink'] = \ {'object_type': 'link', 'destination': 'viewuser.py?cert_id=%s' % quote(visible_user_id), 'class': 'infolink iconspace', 'title': 'View details for %s' % visible_user_id, 'text': ''} vgrids_allow_email = user_dict[CONF].get('VGRIDS_ALLOW_EMAIL', []) vgrids_allow_im = user_dict[CONF].get('VGRIDS_ALLOW_IM', []) if any_vgrid in vgrids_allow_email: email_vgrids = vgrid_access else: email_vgrids = set( vgrids_allow_email).intersection(vgrid_access) if any_vgrid in vgrids_allow_im: im_vgrids = vgrid_access else: im_vgrids = set(vgrids_allow_im).intersection(vgrid_access) for proto in configuration.notify_protocols: if not email_vgrids and proto == 'email': continue if not im_vgrids and proto != 'email': continue if user_obj[CONF].get(proto.upper(), None): link = 'send%slink' % proto user_obj[link] = { 'object_type': 'link', 'destination': "javascript: confirmDialog(%s, '%s', '%s', %s);" % ('sendmsg', 'Really send %s message to %s?' % (proto, visible_user_id), 'request_text', "{cert_id: '%s', 'protocol': '%s'}" % (visible_user_id, proto)), 'class': "%s iconspace" % link, 'title': 'Send %s message to %s' % (proto, visible_user_id), 'text': ''} logger.debug("append user %s" % user_obj) users.append(user_obj) if operation == "show": # insert dummy placeholder to build table user_obj = {'object_type': 'user', 'name': ''} users.append(user_obj) output_objects.append({'object_type': 'user_list', 'pending_updates': pending_updates, 'users': users}) logger.info("%s %s end for %s" % (op_name, operation, client_id)) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) vgrid_name = accepted['vgrid_name'][-1] if not vgrid_is_owner_or_member(vgrid_name, client_id, configuration): output_objects.append({'object_type': 'error_text', 'text': '''You must be an owner or member of %s vgrid to access the workflows.''' % vgrid_name}) return (output_objects, returnvalues.CLIENT_ERROR) title_entry = find_entry(output_objects, 'title') title_entry['text'] = '%s Workflows' \ % configuration.site_vgrid_label title_entry['style'] = themed_styles(configuration) title_entry['javascript'] = \ ''' <script type="text/javascript" src="/images/js/jquery.js"></script> <script type="text/javascript" src="/images/js/jquery.tablesorter.js"></script> <script type="text/javascript" src="/images/js/jquery.tablesorter.pager.js"></script> <script type="text/javascript" src="/images/js/jquery.tablesorter.widgets.js"></script> <script type="text/javascript" src="/images/js/jquery-ui.js"></script> <script type="text/javascript"> $(document).ready(function() { $("#logarea").scrollTop($("#logarea")[0].scrollHeight); // table initially sorted by 0 (last update / date) var sortOrder = [[0,1]]; // use image path for sorting if there is any inside var imgTitle = function(contents) { var key = $(contents).find("a").attr("class"); if (key == null) { key = $(contents).html(); } return key; } $("#workflowstable").tablesorter({widgets: ["zebra", "saveSort"], sortList:sortOrder, textExtraction: imgTitle }) .tablesorterPager({ container: $("#pager"), size: %s }); } ); </script> ''' \ % default_pager_entries output_objects.append({'object_type': 'html_form', 'text': ''' <div id="confirm_dialog" title="Confirm" style="background:#fff;"> <div id="confirm_text"><!-- filled by js --></div> <textarea cols="72" rows="10" id="confirm_input" style="display:none;"></textarea> </div> '''}) output_objects.append({'object_type': 'header', 'text': '%s Workflows for %s' % (configuration.site_vgrid_label, vgrid_name)}) logger.info('vgridworkflows %s' % vgrid_name) # Display active trigger jobs for this vgrid output_objects.append({'object_type': 'sectionheader', 'text': 'Active Trigger Jobs'}) html = '<table><thead><tr>' html += '<th>Job ID</th>' html += '<th>Rule</th>' html += '<th>Path</th>' html += '<th>Change</th>' html += '<th>Time</th>' html += '<th>Status</th>' html += '</tr></thead>' html += '<tbody>' trigger_job_dir = os.path.join(configuration.vgrid_home, os.path.join(vgrid_name, '.%s.jobs' % configuration.vgrid_triggers)) trigger_job_pending_dir = os.path.join(trigger_job_dir, 'pending_states') trigger_job_final_dir = os.path.join(trigger_job_dir, 'final_states' ) if makedirs_rec(trigger_job_pending_dir, logger) \ and makedirs_rec(trigger_job_final_dir, logger): abs_vgrid_dir = '%s/' \ % os.path.abspath(os.path.join(configuration.vgrid_files_home, vgrid_name)) for filename in os.listdir(trigger_job_pending_dir): trigger_job_filepath = \ os.path.join(trigger_job_pending_dir, filename) trigger_job = unpickle(trigger_job_filepath, logger) serverjob_filepath = \ os.path.join(configuration.mrsl_files_dir, os.path.join(client_id_dir(trigger_job['owner' ]), '%s.mRSL' % trigger_job['jobid'])) serverjob = unpickle(serverjob_filepath, logger) if serverjob: if serverjob['STATUS'] in pending_states: trigger_event = trigger_job['event'] trigger_rule = trigger_job['rule'] trigger_action = trigger_event['event_type'] trigger_time = time.ctime(trigger_event['time_stamp' ]) trigger_path = '%s %s' % (trigger_event['src_path' ].replace(abs_vgrid_dir, ''), trigger_event['dest_path' ].replace(abs_vgrid_dir, '')) html += \ '<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></td><td>%s</td>' \ % (trigger_job['jobid'], trigger_rule['rule_id' ], trigger_path, trigger_action, trigger_time, serverjob['STATUS']) elif serverjob['STATUS'] in final_states: src_path = os.path.join(trigger_job_pending_dir, filename) dest_path = os.path.join(trigger_job_final_dir, filename) move_file(src_path, dest_path, configuration) else: logger.error('Trigger job: %s, unknown state: %s' % (trigger_job['jobid'], serverjob['STATUS'])) html += '</tbody>' html += '</table>' output_objects.append({'object_type': 'html_form', 'text': html}) # Display active trigger jobs for this vgrid output_objects.append({'object_type': 'sectionheader', 'text': 'Trigger Log'}) log_content = read_trigger_log(configuration, vgrid_name) output_objects.append({'object_type': 'html_form', 'text': ''' <div class="form_container"> <textarea id="logarea" rows=10 readonly="readonly">%s</textarea> </div> ''' % log_content}) output_objects.append({'object_type': 'sectionheader', 'text': 'Manage Triggers'}) # Always run as rule creator to avoid users being able to act on behalf # of ANY other user using triggers (=exploit) extra_fields = [ ('path', None), ('match_dirs', ['False', 'True']), ('match_recursive', ['False', 'True']), ('changes', [keyword_all] + valid_trigger_changes), ('action', [keyword_auto] + valid_trigger_actions), ('arguments', None), ('run_as', client_id), ] # NOTE: we do NOT show saved template contents - see addvgridtriggers optional_fields = [('rate_limit', None), ('settle_time', None)] (status, oobjs) = vgrid_add_remove_table( client_id, vgrid_name, 'trigger', 'vgridtrigger', configuration, extra_fields, optional_fields, ) output_objects.extend(oobjs) if not status: return (output_objects, returnvalues.SYSTEM_ERROR) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) target_list = accepted['target'] title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'List Scheduled Tasks' header_entry = {'object_type': 'header', 'text': 'Scheduled Tasks'} output_objects.append(header_entry) if not configuration.site_enable_crontab: output_objects.append({ 'object_type': 'text', 'text': ''' Scheduled tasks are disabled on this site. Please contact the site admins %s if you think they should be enabled. ''' % configuration.admin_email }) return (output_objects, returnvalues.OK) logger.info('%s from %s' % (op_name, client_id)) #logger.debug('%s from %s: %s' % (op_name, client_id, accepted)) # Include handy CSRF helpers for use in subsequent client crontab changes csrf_helpers = {'csrf_field': csrf_field} form_method = 'post' csrf_limit = get_csrf_limit(configuration) for target_op in ('addcrontab', 'rmcrontab', 'crontab'): csrf_helpers[target_op] = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) crontab_listing = { 'object_type': 'crontab_listing', 'crontab': [], 'atjobs': [], 'csrf_helpers': csrf_helpers } if not target_list: output_objects.append({ 'object_type': 'error_text', 'text': 'No at/cron target to list!' }) return (output_objects, returnvalues.CLIENT_ERROR) if keyword_all in target_list or 'crontab' in target_list: crontab_contents = load_crontab(client_id, configuration) cronjobs = [] for line in crontab_contents.split('\n'): # Skip comments and blank lines line = line.split('#', 1)[0].strip() if not line: continue cronjobs.append(line) crontab_listing['crontab'] = cronjobs if keyword_all in target_list or 'atjobs' in target_list: atjobs_contents = load_atjobs(client_id, configuration) atjobs = [] for line in atjobs_contents.split('\n'): # Skip comments and blank lines line = line.split('#', 1)[0].strip() if not line: continue atjobs.append(line) crontab_listing['atjobs'] = atjobs output_objects.append(crontab_listing) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) client_dir = client_id_dir(client_id) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) # Please note that base_dir must end in slash to avoid access to other # user dirs when own name is a prefix of another user name base_dir = os.path.abspath(os.path.join(configuration.user_home, client_dir)) + os.sep title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Settings' # prepare support for toggling the views (by css/jquery) title_entry['style'] = themed_styles(configuration) title_entry['style']['skin'] += ''' %s ''' % cm_css title_entry['javascript'] = ''' <script type="text/javascript" src="/images/js/jquery.js"></script> <script type="text/javascript" src="/images/js/jquery-ui.js"></script> %s <script type="text/javascript" > var toggleHidden = function(classname) { // classname supposed to have a leading dot $(classname).toggleClass("hidden"); } $(document).ready(function() { } ); </script> ''' % cm_javascript valid_topics = ['general', 'style'] active_menu = extract_menu(configuration, title_entry) if 'submitjob' in active_menu: valid_topics.append('job') if 'people' in active_menu: valid_topics.append('profile') if configuration.site_script_deps: valid_topics.append('widgets') if configuration.arc_clusters: valid_topics.append('arc') if configuration.site_enable_sftp: valid_topics.append('sftp') if configuration.site_enable_davs: valid_topics.append('webdavs') if configuration.site_enable_ftps: valid_topics.append('ftps') topics = accepted['topic'] # Backwards compatibility if topics and topics[0] == 'ssh': topics[0] = 'sftp' topics = [i for i in topics if i in valid_topics] # Default to general if no valid topics given if not topics: topics.append(valid_topics[0]) topic_titles = dict([(i, i.title()) for i in valid_topics]) for (key, val) in [('sftp', 'SFTP'), ('webdavs', 'WebDAVS'), ('ftps', 'FTPS')]: if key in valid_topics: topic_titles[key] = val output_objects.append({'object_type': 'header', 'text' : 'Settings'}) links = [] for name in valid_topics: active_menu = '' if topics[0] == name: active_menu = 'activebutton' links.append({'object_type': 'link', 'destination': "settings.py?topic=%s" % name, 'class': '%ssettingslink settingsbutton %s' % \ (name, active_menu), 'title': 'Switch to %s settings' % topic_titles[name], 'text' : '%s' % topic_titles[name], }) output_objects.append({'object_type': 'multilinkline', 'links': links, 'sep': ' '}) output_objects.append({'object_type': 'text', 'text': ''}) # load current settings current_settings_dict = load_settings(client_id, configuration) if not current_settings_dict: # no current settings found current_settings_dict = {} if not topics: output_objects.append({'object_type': 'error_text', 'text': 'No valid topics!'}) return (output_objects, returnvalues.CLIENT_ERROR) if 'general' in topics: html = \ ''' <div id="settings"> <form method="post" action="settingsaction.py"> <table class="settings fixedlayout"> <tr class="title"><td class="centertext"> Select your %s settings </td></tr> <tr><td> </td></tr> <tr><td> <input type="hidden" name="topic" value="general" /> Please note that if you want to set multiple values (e.g. addresses) in the same field, you must write each value on a separate line but without blank lines. </td></tr> <tr><td> </td></tr> ''' % configuration.short_title settings_entries = get_settings_specs() for (keyword, val) in settings_entries: if 'SUBMITUI' == keyword and \ 'job' not in valid_topics: continue if 'notify' == val['Context'] and \ keyword.lower() not in configuration.notify_protocols: continue entry = \ """ <tr class='title'><td> %s </td></tr> <tr><td> %s </td></tr> <tr><td> """\ % (keyword.replace('_', ' ').title(), val['Description']) if val['Type'] == 'multiplestrings': try: # get valid choices from conf. multiple selections valid_choices = eval('configuration.%s' % keyword.lower()) current_choice = [] if current_settings_dict.has_key(keyword): current_choice = current_settings_dict[keyword] if len(valid_choices) > 0: entry += '<div class="scrollselect">' for choice in valid_choices: selected = '' if choice in current_choice: selected = 'checked' entry += ''' <input type="checkbox" name="%s" %s value="%s">%s<br />''' % \ (keyword, selected, choice, choice) entry += '</div>' else: entry = '' except: # failed on evaluating configuration.%s area = ''' <textarea id="%s" cols=40 rows=1 name="%s">''' % \ (keyword, keyword) if current_settings_dict.has_key(keyword): area += '\n'.join(current_settings_dict[keyword]) area += '</textarea>' entry += wrap_edit_area(keyword, area, general_edit, 'BASIC') elif val['Type'] == 'string': # get valid choices from conf valid_choices = eval('configuration.%s' % keyword.lower()) current_choice = '' if current_settings_dict.has_key(keyword): current_choice = current_settings_dict[keyword] if len(valid_choices) > 0: entry += '<select name="%s">' % keyword for choice in valid_choices: selected = '' if choice == current_choice: selected = 'selected' entry += '<option %s value="%s">%s</option>'\ % (selected, choice, choice) entry += '</select><br />' else: entry = '' elif val['Type'] == 'boolean': current_choice = '' if current_settings_dict.has_key(keyword): current_choice = current_settings_dict[keyword] entry += '<select name="%s">' % keyword for choice in (True, False): selected = '' if choice == current_choice: selected = 'selected' entry += '<option %s value="%s">%s</option>'\ % (selected, choice, choice) entry += '</select><br />' html += """%s </td></tr> """ % entry html += \ """ <tr><td> <input type="submit" value="Save General Settings" /> </td></tr> </table> </form> </div> """ output_objects.append({'object_type': 'html_form', 'text': html}) if 'job' in topics: mrsl_path = os.path.join(base_dir, default_mrsl_filename) default_mrsl = get_default_mrsl(mrsl_path) html = \ ''' <div id="defaultmrsl"> <form method="post" action="editfile.py"> <table class="defaultjob fixedlayout"> <tr class="title"><td class="centertext"> Default job on submit page </td></tr> <tr><td> </td></tr> <tr><td> If you use the same fields and values in many of your jobs, you can save your preferred job description here to always start out with that description on your submit job page. </td></tr> <tr><td> </td></tr> <tr><td> <input type="hidden" name="path" value="%(mrsl_template)s" /> <input type="hidden" name="newline" value="unix" /> ''' keyword = "defaultjob" area = ''' <textarea id="%(keyword)s" cols=82 rows=25 name="editarea"> %(default_mrsl)s </textarea> ''' html += wrap_edit_area(keyword, area, cm_options, 'BASIC') html += ''' </td></tr> <tr><td> <input type="submit" value="Save Job Template" /> </td></tr> </table> </form> </div> ''' html = html % { 'default_mrsl': default_mrsl, 'mrsl_template': default_mrsl_filename, 'site': configuration.short_title, 'keyword': keyword } output_objects.append({'object_type': 'html_form', 'text': html}) if 'style' in topics: css_path = os.path.join(base_dir, default_css_filename) default_css = get_default_css(css_path) html = \ ''' <div id="defaultcss"> <form method="post" action="editfile.py"> <table class="defaultstyle fixedlayout"> <tr class="title"><td class="centertext"> Default CSS (style) for all pages </td></tr> <tr><td> </td></tr> <tr><td> If you want to customize the look and feel of the %(site)s web interfaces you can override default values here. If you leave the style file blank you will just use the default style.<br /> You can copy paste from the available style file links below if you want to override specific parts.<br /> <div class="warningtext">Please note that you can not save an empty style file, but must at least leave a blank line to use defaults. Additionally some errors in your style code may potentially cause severe corruption in your page layouts, so it may be a good idea to keep another browser tab/window ready to (re)move your .default.css file to restore the defaults while experimenting here. </div> </td></tr> <tr><td> <a class="urllink" href="/images/default.css">default</a> , <a class="urllink" href="/images/bluesky.css">bluesky</a> </td></tr> <tr><td> </td></tr> <tr><td> <input type="hidden" name="path" value="%(css_template)s" /> <input type="hidden" name="newline" value="unix" /> ''' keyword = "defaultstyle" area = ''' <textarea id="%(keyword)s" cols=82 rows=25 min_len=1 name="editarea"> %(default_css)s </textarea> ''' html += wrap_edit_area(keyword, area, style_edit) html += ''' </td></tr> <tr><td> <input type="submit" value="Save Style Settings" /> </td></tr> </table> </form> </div> ''' html = html % { 'default_css': default_css, 'css_template': default_css_filename, 'site': configuration.short_title, 'keyword': keyword } output_objects.append({'object_type': 'html_form', 'text': html}) if 'widgets' in topics: # load current widgets current_widgets_dict = load_widgets(client_id, configuration) if not current_widgets_dict: # no current widgets found current_widgets_dict = {} show_widgets = current_settings_dict.get('ENABLE_WIDGETS', True) if show_widgets: edit_widgets = '''You can simply copy/paste from the available widget file links below if you want to reuse existing widgets.<br /> </td></tr> <tr><td> <a class="urllink" href="/images/widgets/hello-grid.app">hello grid</a>, <a class="urllink" href="/images/widgets/simple-calendar.app">simple calendar</a>, <a class="urllink" href="/images/widgets/calendar.app">calendar</a>, <a class="urllink" href="/images/widgets/gcal.app">google calendar</a>, <a class="urllink" href="/images/widgets/calculator.app">calculator</a>, <a class="urllink" href="/images/widgets/localrss.app">local rss reader</a>, <a class="urllink" href="/images/widgets/rss.app">rss reader</a>, <a class="urllink" href="/images/widgets/clock.app">clock</a>, <a class="urllink" href="/images/widgets/weather.app">weather</a>, <a class="urllink" href="/images/widgets/progressbar.app">progress bar</a>, <a class="urllink" href="/images/widgets/simple-move.app">simple-move</a>, <a class="urllink" href="/images/widgets/portlets.app">portlets</a>, <a class="urllink" href="/images/widgets/countdown.app">countdown</a>, <a class="urllink" href="/images/widgets/sparkline.app">mini chart</a>, <a class="urllink" href="/images/widgets/piechart.app">pie chart</a>, <a class="urllink" href="/images/widgets/simple-jobmon.app">simple-jobmon</a>, <a class="urllink" href="/images/widgets/cert-countdown.app">certificate countdown</a>, <a class="urllink" href="/images/widgets/disk-use.app">disk use progress bar</a>, <a class="urllink" href="/images/widgets/jobs-stats.app">jobs stats table</a>, <a class="urllink" href="/images/widgets/jobs-stats-chart.app">jobs stats chart</a>, <a class="urllink" href="/images/widgets/daily-wm-comic.app">Daily WulffMorgenthaler comic</a>, <a class="urllink" href="/images/widgets/kunet-login.app">KUnet login</a> <a class="urllink" href="/images/widgets/tdchotspot-login.app">TDC Hotspot login</a> </td></tr> <tr><td> <div class="warningtext">Please note that the widgets parser is rather grumpy so you may have to avoid blank lines in your widget code below. Additionally any errors in your widgets code may cause severe corruption in your pages, so it may be a good idea to keep another browser tab/window ready for emergency disabling of widgets while experimenting here.</div> </td></tr> <tr><td> <input type="hidden" name="topic" value="widgets" /> </td></tr> <tr><td> ''' html = \ '''<div id="widgets"> <form method="post" action="settingsaction.py"> <table class="widgets fixedlayout"> <tr class="title"><td class="centertext"> Default user defined widgets for all pages </td></tr> <tr><td> </td></tr> <tr><td> If you want to customize the look and feel of the %s web interfaces you can add your own widgets here. If you leave the widgets blank you will just get the default empty widget spaces.<br /> ''' % configuration.short_title widgets_entries = get_widgets_specs() widgets_html = '' for (keyword, val) in widgets_entries: widgets_html += \ """ <tr class=title><td> %s </td></tr> <tr><td> %s </td></tr> <tr><td> """\ % (keyword.replace('_', ' ').title(), val['Description']) if val['Type'] == 'multiplestrings': try: # get valid choices from conf. multiple selections valid_choices = eval('configuration.%s' % keyword.lower()) current_choice = [] if current_widgets_dict.has_key(keyword): current_choice = current_widgets_dict[keyword] if len(valid_choices) > 0: widgets_html += '<div class="scrollselect">' for choice in valid_choices: selected = '' if choice in current_choice: selected = 'checked' widgets_html += ''' <input type="checkbox" name="%s" %s value="%s">%s<br />'''\ % (keyword, selected, choice, choice) widgets_html += '</div>' except: area = \ """<textarea id='%s' cols=78 rows=10 name='%s'>""" % \ (keyword, keyword) if current_widgets_dict.has_key(keyword): area += '\n'.join(current_widgets_dict[keyword]) area += '</textarea>' widgets_html += wrap_edit_area(keyword, area, widgets_edit) if show_widgets: edit_widgets += ''' %s <tr><td> <input type="submit" value="Save Widgets Settings" /> </td></tr> ''' % widgets_html else: edit_widgets = ''' <br/> <div class="warningtext"> Widgets are disabled on your <em>General</em> settings page. Please enable them there first if you want to customize your grid pages. </div> ''' html += \ ''' %s </table> </form> </div> ''' % edit_widgets output_objects.append({'object_type': 'html_form', 'text': html}) if 'profile' in topics: # load current profile current_profile_dict = load_profile(client_id, configuration) if not current_profile_dict: # no current profile found current_profile_dict = {} (got_list, all_vgrids) = vgrid_list_vgrids(configuration) if not got_list: all_vgrids = [] all_vgrids.append(any_vgrid) all_vgrids.sort() configuration.vgrids_allow_email = all_vgrids configuration.vgrids_allow_im = all_vgrids images = [] for path in os.listdir(base_dir): real_path = os.path.join(base_dir, path) if os.path.splitext(path)[1].strip('.') in profile_img_extensions \ and os.path.getsize(real_path) < profile_img_max_kb*1024: images.append(path) configuration.public_image = images html = \ ''' <div id="profile"> <form method="post" action="settingsaction.py"> <table class="profile fixedlayout"> <tr class="title"><td class="centertext"> Public profile information visible to other users. </td></tr> <tr><td> </td></tr> <tr><td> If you want to let other users know more about you can add your own text here. If you leave the text area blank you will just get the default empty profile information.<br /> </td></tr> <tr><td> <div class="warningtext">Please note that the profile parser is rather grumpy so you may have to avoid blank lines in your text below. </div> </td></tr> <tr><td> <input type="hidden" name="topic" value="profile" /> </td></tr> <tr><td> ''' profile_entries = get_profile_specs() for (keyword, val) in profile_entries: # Mask VGrid name if configured mask_title = keyword.replace( 'VGRID', configuration.site_vgrid_label.upper()) mask_desc = val['Description'].replace( 'VGrid', configuration.site_vgrid_label) html += \ """ <tr class=title><td> %s </td></tr> <tr><td> %s </td></tr> <tr><td> """ % (mask_title.replace('_', ' ').title(), html_escape(mask_desc)) if val['Type'] == 'multiplestrings': try: # get valid choices from conf. multiple selections valid_choices = eval('configuration.%s' % keyword.lower()) current_choice = [] if current_profile_dict.has_key(keyword): current_choice = current_profile_dict[keyword] if len(valid_choices) > 0: html += '<div class="scrollselect">' for choice in valid_choices: selected = '' if choice in current_choice: selected = 'checked' html += ''' <input type="checkbox" name="%s" %s value="%s">%s<br />''' % \ (keyword, selected, choice, choice) html += '</div>' except: area = \ """<textarea id='%s' cols=78 rows=10 name='%s'>""" % \ (keyword, keyword) if current_profile_dict.has_key(keyword): area += '\n'.join(current_profile_dict[keyword]) area += '</textarea>' html += wrap_edit_area(keyword, area, profile_edit) elif val['Type'] == 'boolean': valid_choices = [True, False] current_choice = '' if current_profile_dict.has_key(keyword): current_choice = current_profile_dict[keyword] if len(valid_choices) > 0: html += '<select name="%s">' % keyword for choice in valid_choices: selected = '' if choice == current_choice: selected = 'selected' html += '<option %s value="%s">%s</option>'\ % (selected, choice, choice) html += '</select><br />' html += ''' <tr><td> <input type="submit" value="Save Profile Settings" /> </td></tr> </table> </form> </div> ''' output_objects.append({'object_type': 'html_form', 'text': html}) if 'sftp' in topics: # load current ssh/sftp current_ssh_dict = load_ssh(client_id, configuration) if not current_ssh_dict: # no current ssh found current_ssh_dict = {} default_authkeys = current_ssh_dict.get('authkeys', '') default_authpassword = current_ssh_dict.get('authpassword', '') username = client_alias(client_id) if configuration.user_sftp_alias: username = extract_field(client_id, configuration.user_sftp_alias) create_alias_link(username, client_id, configuration.user_home) sftp_server = configuration.user_sftp_show_address sftp_port = configuration.user_sftp_show_port html = \ ''' <div id="sshaccess"> <form method="post" action="settingsaction.py"> <table class="sshsettings fixedlayout"> <tr class="title"><td class="centertext"> SFTP access to your %(site)s account </td></tr> <tr><td> </td></tr> <tr><td> You can configure SFTP login to your %(site)s account for efficient file access. On Linux/UN*X it also allows transparent access through SSHFS. <br/> <h3>Login Details</h3> <ul> <li>Host <em>%(sftp_server)s</em></li> <li>Port <em>%(sftp_port)s</em></li> <li>Username <em>%(username)s</em></li> <li>%(auth_methods)s <em>as you choose below</em></li> </ul> </td></tr> <tr><td> <input type="hidden" name="topic" value="sftp" /> <div class="div-sftp-client-notes hidden"> <a href="javascript:toggleHidden('.div-sftp-client-notes');" class="removeitemlink" title="Toggle view"> Show less SFTP client details...</a> <h3>Graphical SFTP access</h3> The FireFTP plugin for Firefox is known to generally work for graphical access to your %(site)s home over SFTP. Enter the following values in the FireFTP Account Manager: <pre> Host %(sftp_server)s Login %(username)s Password YOUR_PASSWORD_HERE (passphrase if you configured public key access) Security SFTP Port %(sftp_port)s Private Key ~/.mig/key.pem (if you configured public key access) </pre> other graphical clients may work as well. <h3>Command line SFTP/SSHFS access on Linux/UN*X</h3> Save something like the following lines in your local ~/.ssh/config to avoid typing the full login details every time:<br /> <pre> Host %(sftp_server)s Hostname %(sftp_server)s User %(username)s Port %(sftp_port)s IdentityFile ~/.mig/key.pem </pre> From then on you can use sftp and sshfs to access your %(site)s home: <pre> sftp %(sftp_server)s </pre> <pre> sshfs %(sftp_server)s: mig-home -o uid=$(id -u) -o gid=$(id -g) </pre> You can also integrate with ordinary mounts by adding a line like: <pre> sshfs#%(username)s@%(sftp_server)s: /home/USER/mig-home fuse noauto,user,port=%(sftp_port)d 0 0 </pre> to your /etc/fstab . </div> <div class="div-sftp-client-notes"> <a href="javascript:toggleHidden('.div-sftp-client-notes');" class="additemlink" title="Toggle view">Show more SFTP client details... </a> </div> ''' keyword_keys = "authkeys" if 'publickey' in configuration.user_sftp_auth: html += ''' </td></tr> <tr><td> <h3>Authorized Public Keys</h3> You can use any existing RSA key, or create a new one. If you signed up with a x509 user certificate, you should also have received such a key.pem along with your user certificate. In any case you need to save the contents of the corresponding public key (X.pub) in the text area below, to be able to connect with username and key as described in the Login Details. <br/> ''' area = ''' <textarea id="%(keyword_keys)s" cols=82 rows=5 name="publickeys"> %(default_authkeys)s </textarea> ''' html += wrap_edit_area(keyword_keys, area, ssh_edit, 'BASIC') html += ''' (leave empty to disable sftp access with public keys) </td></tr> ''' keyword_password = "******" if 'password' in configuration.user_sftp_auth: # We only want a single password and a masked input field html += ''' <tr><td> <h3>Authorized Password</h3> Please enter and save your desired password in the text field below, to be able to connect with username and password as described in the Login Details. <br/> <input type=password id="%(keyword_password)s" size=40 name="password" value="%(default_authpassword)s" /> (leave empty to disable sftp access with password) </td></tr> ''' html += ''' <tr><td> <input type="submit" value="Save SFTP Settings" /> </td></tr> ''' html += ''' </table> </form> </div> ''' html = html % { 'default_authkeys': default_authkeys, 'default_authpassword': default_authpassword, 'site': configuration.short_title, 'keyword_keys': keyword_keys, 'keyword_password': keyword_password, 'username': username, 'sftp_server': sftp_server, 'sftp_port': sftp_port, 'auth_methods': ' / '.join(configuration.user_sftp_auth).title(), } output_objects.append({'object_type': 'html_form', 'text': html}) if 'webdavs' in topics: # load current davs current_davs_dict = load_davs(client_id, configuration) if not current_davs_dict: # no current davs found current_davs_dict = {} default_authkeys = current_davs_dict.get('authkeys', '') default_authpassword = current_davs_dict.get('authpassword', '') username = client_alias(client_id) if configuration.user_davs_alias: username = extract_field(client_id, configuration.user_davs_alias) create_alias_link(username, client_id, configuration.user_home) davs_server = configuration.user_davs_show_address davs_port = configuration.user_davs_show_port html = \ ''' <div id="davsaccess"> <form method="post" action="settingsaction.py"> <table class="davssettings fixedlayout"> <tr class="title"><td class="centertext"> WebDAVS access to your %(site)s account </td></tr> <tr><td> </td></tr> <tr><td> You can configure WebDAVS login to your %(site)s account for transparent file access from your PC or workstation.<br/> <h3>Login Details</h3> <ul> <li>Host <em>%(davs_server)s</em></li> <li>Port <em>%(davs_port)s</em></li> <li>Username <em>%(username)s</em></li> <li>%(auth_methods)s <em>as you choose below</em></li> </ul> </td></tr> <tr><td> <input type="hidden" name="topic" value="webdavs" /> <div class="div-webdavs-client-notes hidden"> <a href="javascript:toggleHidden('.div-webdavs-client-notes');" class="removeitemlink" title="Toggle view"> Show less WebDAVS client details...</a> <h3>Graphical WebDAVS access</h3> Several native file browsers and web browsers are known to generally work for graphical access to your %(site)s home over WebDAVS. <br /> Enter the address https://%(davs_server)s:%(davs_port)s and when fill in the login details: <pre> Username %(username)s Password YOUR_PASSWORD_HERE </pre> other graphical clients should work as well. <h3>Command line WebDAVS access on Linux/UN*X</h3> Save something like the following lines in your local ~/.netrc to avoid typing the full login details every time:<br /> <pre> machine %(davs_server)s login %(username)s password YOUR_PASSWORD_HERE </pre> From then on you can use e.g. cadaver or fusedav to access your %(site)s home: <pre> cadaver https://%(davs_server)s:%(davs_port)s </pre> <pre> fusedav https://%(davs_server)s:%(davs_port)s mig-home -o uid=$(id -u) -o gid=$(id -g) </pre> </div> <div class="div-webdavs-client-notes"> <a href="javascript:toggleHidden('.div-webdavs-client-notes');" class="additemlink" title="Toggle view"> Show more WebDAVS client details...</a> </div> ''' keyword_keys = "authkeys" if 'publickey' in configuration.user_davs_auth: html += ''' </td></tr> <tr><td> <h3>Authorized Public Keys</h3> You can use any existing RSA key, including the key.pem you received along with your user certificate, or create a new one. In any case you need to save the contents of the corresponding public key (X.pub) in the text area below, to be able to connect with username and key as described in the Login Details. <br/>''' area = ''' <textarea id="%(keyword_keys)s" cols=82 rows=5 name="publickeys"> %(default_authkeys)s </textarea> ''' html += wrap_edit_area(keyword_keys, area, davs_edit, 'BASIC') html += ''' (leave empty to disable davs access with public keys) </td></tr> ''' keyword_password = "******" if 'password' in configuration.user_davs_auth: # We only want a single password and a masked input field html += ''' <tr><td> <h3>Authorized Password</h3> Please enter and save your desired password in the text field below, to be able to connect with username and password as described in the Login Details. <br/> <input type=password id="%(keyword_password)s" size=40 name="password" value="%(default_authpassword)s" /> (leave empty to disable davs access with password) </td></tr> ''' html += ''' <tr><td> <input type="submit" value="Save WebDAVS Settings" /> </td></tr> ''' html += ''' </table> </form> </div> ''' html = html % { 'default_authkeys': default_authkeys, 'default_authpassword': default_authpassword, 'site': configuration.short_title, 'keyword_keys': keyword_keys, 'keyword_password': keyword_password, 'username': username, 'davs_server': davs_server, 'davs_port': davs_port, 'auth_methods': ' / '.join(configuration.user_davs_auth).title(), } output_objects.append({'object_type': 'html_form', 'text': html}) if 'ftps' in topics: # load current ftps current_ftps_dict = load_ftps(client_id, configuration) if not current_ftps_dict: # no current ftps found current_ftps_dict = {} default_authkeys = current_ftps_dict.get('authkeys', '') default_authpassword = current_ftps_dict.get('authpassword', '') username = client_alias(client_id) if configuration.user_ftps_alias: username = extract_field(client_id, configuration.user_ftps_alias) create_alias_link(username, client_id, configuration.user_home) ftps_server = configuration.user_ftps_show_address ftps_ctrl_port = configuration.user_ftps_show_ctrl_port html = \ ''' <div id="ftpsaccess"> <form method="post" action="settingsaction.py"> <table class="ftpssettings fixedlayout"> <tr class="title"><td class="centertext"> FTPS access to your %(site)s account </td></tr> <tr><td> </td></tr> <tr><td> You can configure FTPS login to your %(site)s account for efficient file access.<br/> <h3>Login Details</h3> <ul> <li>Host <em>%(ftps_server)s</em></li> <li>Port <em>%(ftps_ctrl_port)s</em></li> <li>Username <em>%(username)s</em></li> <li>%(auth_methods)s <em>as you choose below</em></li> </ul> </td></tr> <tr><td> <input type="hidden" name="topic" value="ftps" /> <div class="div-ftps-client-notes hidden"> <a href="javascript:toggleHidden('.div-ftps-client-notes');" class="removeitemlink" title="Toggle view"> Show less FTPS client details...</a> <h3>Graphical FTPS access</h3> The FireFTP plugin for Firefox is known to generally work for graphical access to your %(site)s home over FTPS. Enter the following values in the FireFTP Account Manager: <pre> Host %(ftps_server)s Login %(username)s Password YOUR_PASSWORD_HERE Security FTPS Port %(ftps_ctrl_port)s </pre> Other FTP clients and web browsers may work as well if you enter the address ftps://%(ftps_server)s:%(ftps_ctrl_port)s and fill in the login details when prompted: <pre> Username %(username)s Password YOUR_PASSWORD_HERE </pre> <h3>Command line FTPS access on Linux/UN*X</h3> Save something like the following lines in your local ~/.netrc to avoid typing the full login details every time:<br /> <pre> machine %(ftps_server)s login %(username)s password YOUR_PASSWORD_HERE </pre> From then on you can use e.g. lftp or CurlFtpFS to access your %(site)s home: <!-- TODO: we need to provide the intermediate cert for server cert check like this set ssl:ca-file sub.class1.server.ca.pem --> <pre> lftp -e "set ssl:verify-certificate no; set ftp:ssl-protect-data on" \\ -p %(ftps_ctrl_port)s %(ftps_server)s </pre> <pre> curlftpfs -o ssl %(ftps_server)s:%(ftps_ctrl_port)s mig-home \\ -o user=%(username)s -ouid=$(id -u) -o gid=$(id -g) -o no_verify_peer </pre> </div> <div class="div-ftps-client-notes"> <a href="javascript:toggleHidden('.div-ftps-client-notes');" class="additemlink" title="Toggle view">Show more FTPS client details... </a> </div> ''' keyword_keys = "authkeys" if 'publickey' in configuration.user_ftps_auth: html += ''' </td></tr> <tr><td> <h3>Authorized Public Keys</h3> You can use any existing RSA key, including the key.pem you received along with your user certificate, or create a new one. In any case you need to save the contents of the corresponding public key (X.pub) in the text area below, to be able to connect with username and key as described in the Login Details. <br/> ''' area = ''' <textarea id="%(keyword_keys)s" cols=82 rows=5 name="publickeys"> %(default_authkeys)s </textarea> ''' html += wrap_edit_area(keyword_keys, area, ftps_edit, 'BASIC') html += ''' (leave empty to disable ftps access with public keys) </td></tr> ''' keyword_password = "******" if 'password' in configuration.user_ftps_auth: # We only want a single password and a masked input field html += ''' <tr><td> <h3>Authorized Password</h3> Please enter and save your desired password in the text field below, to be able to connect with username and password as described in the Login Details. <br/> <input type=password id="%(keyword_password)s" size=40 name="password" value="%(default_authpassword)s" /> (leave empty to disable ftps access with password) </td></tr> ''' html += ''' <tr><td> <input type="submit" value="Save FTPS Settings" /> </td></tr> ''' html += ''' </table> </form> </div> ''' html = html % { 'default_authkeys': default_authkeys, 'default_authpassword': default_authpassword, 'site': configuration.short_title, 'keyword_keys': keyword_keys, 'keyword_password': keyword_password, 'username': username, 'ftps_server': ftps_server, 'ftps_ctrl_port': ftps_ctrl_port, 'auth_methods': ' / '.join(configuration.user_ftps_auth).title(), } output_objects.append({'object_type': 'html_form', 'text': html}) # if ARC-enabled server: if 'arc' in topics: # provide information about the available proxy, offer upload try: home_dir = os.path.normpath(base_dir) session_Ui = arc.Ui(home_dir, require_user_proxy=True) proxy = session_Ui.getProxy() if proxy.IsExpired(): # can rarely happen, constructor will throw exception output_objects.append({'object_type': 'text', 'text': 'Proxy certificate is expired.'}) else: output_objects.append({'object_type': 'text', 'text': 'Proxy for %s' \ % proxy.GetIdentitySN()}) output_objects.append( {'object_type': 'text', 'text': 'Proxy certificate will expire on %s (in %s sec.)' % (proxy.Expires(), proxy.getTimeleft()) }) except arc.NoProxyError, err: output_objects.append({'object_type':'warning', 'text': 'No proxy certificate to load: %s' \ % err.what()}) output_objects = output_objects + arc.askProxy()
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) if not correct_handler('POST'): output_objects.append( {'object_type': 'error_text', 'text' : 'Only accepting POST requests to prevent unintended updates'}) return (output_objects, returnvalues.CLIENT_ERROR) vgrid_name = accepted['vgrid_name'][-1] flags = ''.join(accepted['flags']) cert_id = accepted['cert_id'][-1] cert_dir = client_id_dir(cert_id) # inherited vgrid membership inherit_vgrid_member = False title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Remove %s' % configuration.site_vgrid_label output_objects.append({'object_type': 'header', 'text' : 'Remove %s Owner' % \ configuration.site_vgrid_label}) # Validity of user and vgrid names is checked in this init function so # no need to worry about illegal directory traversal through variables (ret_val, msg, _) = \ init_vgrid_script_add_rem(vgrid_name, client_id, cert_id, 'owner', configuration) if not ret_val: output_objects.append({'object_type': 'error_text', 'text' : msg}) return (output_objects, returnvalues.CLIENT_ERROR) # don't remove if not already an owner if not vgrid_is_owner(vgrid_name, cert_id, configuration): output_objects.append({'object_type': 'error_text', 'text' : '%s is not an owner of %s or a parent %s.' % (cert_id, vgrid_name, configuration.site_vgrid_label)}) return (output_objects, returnvalues.CLIENT_ERROR) # we need the local owners file to detect inherited ownerships (status, owners_direct) = vgrid_owners(vgrid_name, configuration, False) (all_status, owners) = vgrid_owners(vgrid_name, configuration, True) if not status or not all_status: logger.error('Error loading owners for %s: %s / %s' % (vgrid_name, owners_direct, owners)) output_objects.append({'object_type': 'error_text', 'text' : 'An internal error occurred, error conditions have been logged.'}) output_objects.append({'object_type': 'text', 'text' : ''' You can help us fix the problem by notifying the administrators via mail about what you wanted to do when the error happened.'''}) return (output_objects, returnvalues.CLIENT_ERROR) # find out whether to just remove an owner or delete the whole thing. # ask about delete if last or no direct owners. if len(owners_direct) > 1: logger.debug('Removing %s, one of several owners, from %s.' % (cert_id, vgrid_name)) if not (cert_id in owners_direct): # the owner owns an upper vgrid, ownership is inherited # cannot remove, not last (inherited) owner logger.debug('Cannot delete: Inherited ownership.' + '\n Owners: %s,\n Direct owners: %s.' % (owners, owners_direct)) output_objects.append({'object_type': 'error_text', 'text' : '''%s is owner of a parent %s. Owner removal has to be performed at the topmost vgrid''' % \ (cert_id, configuration.site_vgrid_label)}) return (output_objects, returnvalues.CLIENT_ERROR) else: # Remove any tracker admin rights if configuration.trac_admin_path: public_tracker_dir = \ os.path.abspath(os.path.join( configuration.vgrid_public_base, vgrid_name, '.vgridtracker')) private_tracker_dir = \ os.path.abspath(os.path.join( configuration.vgrid_private_base, vgrid_name, '.vgridtracker')) vgrid_tracker_dir = \ os.path.abspath(os.path.join( configuration.vgrid_files_home, vgrid_name, '.vgridtracker')) for tracker_dir in [public_tracker_dir, private_tracker_dir, vgrid_tracker_dir]: if not rm_tracker_admin(configuration, cert_id, vgrid_name, tracker_dir, output_objects): return (output_objects, returnvalues.SYSTEM_ERROR) user_dir = os.path.abspath(os.path.join(configuration.user_home, cert_dir)) + os.sep # Do not touch vgrid share if still a member of a parent vgrid if vgrid_is_member(vgrid_name, cert_id, configuration): # list is in top-down order parent_vgrids = vgrid_list_parents(vgrid_name, configuration) inherit_vgrid_member = vgrid_name for parent in parent_vgrids: if vgrid_is_member(parent, cert_id, configuration, recursive=False): inherit_vgrid_member = parent break output_objects.append( {'object_type': 'text', 'text' : '''NOTE: %s is still a member of parent %s %s. Preserving access to corresponding %s.''' % \ (cert_id, configuration.site_vgrid_label, inherit_vgrid_member, configuration.site_vgrid_label) }) else: (success, msg) = unlink_share(user_dir, vgrid_name) if not success: logger.error('Could not remove share link: %s.' % msg) output_objects.append({'object_type': 'error_text', 'text' : 'Could not remove share links: %s.' % msg}) return (output_objects, returnvalues.SYSTEM_ERROR) # unlink shared web folders (success, msg) = unlink_web_folders(user_dir, vgrid_name) if not success: logger.error('Could not remove web links: %s.' % msg) output_objects.append({'object_type': 'error_text', 'text' : 'Could not remove web links: %s.' % msg}) return (output_objects, returnvalues.SYSTEM_ERROR) # remove user from saved owners list (rm_status, rm_msg) = vgrid_remove_owners(configuration, vgrid_name, [cert_id]) if not rm_status: output_objects.append({'object_type': 'error_text', 'text' : '%s of owners of %s' % (rm_msg, vgrid_name)}) return (output_objects, returnvalues.SYSTEM_ERROR) # Any parent vgrid membership is left untouched here as we only # force a normal refresh in unmap_inheritance unmap_inheritance(configuration, vgrid_name, cert_id) output_objects.append({'object_type': 'text', 'text' : '%s successfully removed as owner of %s!' % (cert_id, vgrid_name)}) output_objects.append({'object_type': 'link', 'destination': 'adminvgrid.py?vgrid_name=%s' % vgrid_name, 'text': 'Back to administration for %s' % vgrid_name}) return (output_objects, returnvalues.OK) else: # no more direct owners - we try to remove this VGrid logger.debug('Leave %s from %s with no more direct owners: delete' % (vgrid_name, cert_id)) if not force(flags): output_objects.append({'object_type': 'text', 'text' : ''' No more direct owners of %s - leaving will result in the %s getting deleted. Please use either of the links below to confirm or cancel. ''' % (vgrid_name, configuration.site_vgrid_label)}) js_name = 'rmvgridowner%s' % hexlify(vgrid_name) helper = html_post_helper(js_name, 'rmvgridowner.py', {'vgrid_name': vgrid_name, 'cert_id': cert_id, 'flags': 'f'}) output_objects.append({'object_type': 'html_form', 'text': helper}) output_objects.append({'object_type': 'link', 'destination': "javascript: %s();" % js_name, 'class': 'removelink', 'text': 'Really leave and delete %s' % vgrid_name}) output_objects.append({'object_type': 'text', 'text' : ''}) output_objects.append({'object_type': 'link', 'destination': 'adminvgrid.py?vgrid_name=%s' % vgrid_name, 'text': 'Back to administration for %s' % vgrid_name}) return (output_objects, returnvalues.OK) # check if any resources participate or sub-vgrids depend on this one (status, subs) = vgrid_list_subvgrids(vgrid_name, configuration) if not status: logger.error('Error loading sub-%ss for %s: %s)' % (configuration.site_vgrid_label, vgrid_name, subs)) output_objects.append({'object_type': 'error_text', 'text' : ''' An internal error occurred, error conditions have been logged.'''}) output_objects.append({'object_type': 'text', 'text' : ''' You can help us fix the problem by notifying the administrators via mail about what you wanted to do when the error happened.'''}) return (output_objects, returnvalues.CLIENT_ERROR) if len(subs) > 0: logger.debug('Cannot delete: still has sub-%ss %s.' % (configuration.site_vgrid_label, subs)) output_objects.append({'object_type': 'error_text', 'text' : \ '%s has sub-structures and cannot be deleted.' % vgrid_name}) output_objects.append({'object_type': 'text', 'text' : ''' To leave (and delete) %s, first remove its sub-structures: %s.''' % (vgrid_name, ', '.join(subs))}) return (output_objects, returnvalues.CLIENT_ERROR) # we consider the local members and resources here, not inherited ones (member_status, members_direct) = vgrid_members(vgrid_name, configuration, False) (resource_status, resources_direct) = vgrid_resources(vgrid_name, configuration, False) if not member_status or not resource_status: logger.warning('failed to load %s members or resources: %s %s' % (vgrid_name, members_direct, resources_direct)) output_objects.append({'object_type': 'error_text', 'text' : \ 'could not load %s members or resources for %s.' % \ (configuration.site_vgrid_label, vgrid_name)}) return (output_objects, returnvalues.SYSTEM_ERROR) if len(resources_direct) > 0: logger.debug('Cannot delete: still has direct resources %s.' % resources_direct) output_objects.append({'object_type': 'error_text', 'text' : \ '%s still has resources and cannot be deleted.' % vgrid_name}) output_objects.append({'object_type': 'text', 'text' : ''' To leave (and delete) %s, first remove the participating resources.''' % vgrid_name}) return (output_objects, returnvalues.CLIENT_ERROR) if len(members_direct) > 0: logger.debug('Cannot delete: still has direct members %s.' % members_direct) output_objects.append({'object_type': 'error_text', 'text' : \ '%s still has members and cannot be deleted.' % vgrid_name}) output_objects.append({'object_type': 'text', 'text' : ''' To leave (and delete) %s, first remove all members.''' % vgrid_name}) return (output_objects, returnvalues.CLIENT_ERROR) # When reaching here, OK to remove the VGrid. # if top-level: unlink, remove all files and directories, # in all cases: remove configuration entry for the VGrid if (cert_id in owners_direct): # owner owns this vgrid, direct ownership logger.debug('%s looks like a top-level %s.' % \ (configuration.site_vgrid_label, vgrid_name)) logger.debug('Deleting all related files.') user_dir = os.path.abspath(os.path.join(configuration.user_home, cert_dir)) + os.sep (share_lnk, msg1) = unlink_share(user_dir, vgrid_name) (web_lnk, msg1) = unlink_web_folders(user_dir, vgrid_name) (abandoned, msg2) = abandon_vgrid_files(vgrid_name, configuration) else: # owner owns an upper vgrid, ownership is inherited logger.debug('%s looks like a sub-%s, ownership inherited.' % (vgrid_name, configuration.site_vgrid_label)) logger.debug('Only removing entry, leaving files in place.') share_lnk = True web_lnk = True abandoned = True msg1 = '' msg2 = '' (removed, msg3) = remove_vgrid_entry(vgrid_name, configuration) output_objects.append({'object_type': 'text', 'text' : '%s has been removed with last owner.' % vgrid_name}) output_objects.append({'object_type': 'link', 'destination': 'vgridadmin.py', 'text': 'Back to the overview.'}) if not share_lnk or not web_lnk or not abandoned or not removed: logger.error('Errors while removing %s:\n%s.' % (vgrid_name, '\n'.join([msg1,msg2,msg3]))) output_objects.append({'object_type': 'error_text', 'text' : ''' An internal error occurred, error conditions have been logged.'''}) output_objects.append({'object_type': 'text', 'text' : ''' You can help us fix the problem by notifying the administrators via mail about what you wanted to do when the error happened.'''}) return (output_objects, returnvalues.CLIENT_ERROR) else: # Remove vgrid from vgrid cache (after deleting all) unmap_vgrid(configuration, vgrid_name) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = initialize_main_variables(client_id, op_header=False) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) unique_res_names = accepted["unique_resource_name"] (re_stat, re_list) = list_runtime_environments(configuration) if not re_stat: logger.warning("Failed to load list of runtime environments") output_objects.append({"object_type": "error_text", "text": "Error getting list of runtime environments"}) return (output_objects, returnvalues.SYSTEM_ERROR) title_entry = find_entry(output_objects, "title") title_entry["text"] = "Resource Management" title_entry["style"] = themed_styles(configuration) title_entry[ "javascript" ] = """ <script type="text/javascript" src="/images/js/jquery.js"></script> <script type="text/javascript" src="/images/js/jquery-ui.js"></script> <script type="text/javascript" src="/images/js/jquery.confirm.js"></script> <script type="text/javascript" > var toggleHidden = function(classname) { // classname supposed to have a leading dot $(classname).toggleClass("hidden"); } $(document).ready(function() { // init confirmation dialog $("#confirm_dialog").dialog( // see http://jqueryui.com/docs/dialog/ for options { autoOpen: false, modal: true, closeOnEscape: true, width: 500, buttons: { "Cancel": function() { $("#" + name).dialog("close"); } } }); } ); </script> """ output_objects.append({"object_type": "header", "text": " Resource Management"}) output_objects.append({"object_type": "sectionheader", "text": "%s Resources Owned" % configuration.short_title}) quick_links = [{"object_type": "text", "text": "Quick links to all your resources and individual management"}] quick_links.append({"object_type": "html_form", "text": '<div class="hidden quicklinks">'}) quick_links.append( { "object_type": "link", "destination": "javascript:toggleHidden('.quicklinks');", "class": "removeitemlink", "title": "Toggle view", "text": "Hide quick links", } ) quick_links.append({"object_type": "text", "text": ""}) quick_res = {} quick_links_index = len(output_objects) output_objects.append({"object_type": "sectionheader", "text": ""}) output_objects.append( { "object_type": "html_form", "text": """ <div id="confirm_dialog" title="Confirm" style="background:#fff;"> <div id="confirm_text"><!-- filled by js --></div> <textarea cols="40" rows="4" id="confirm_input" style="display:none;"></textarea> </div> """, } ) owned = 0 res_map = get_resource_map(configuration) for unique_resource_name in res_map.keys(): if sandbox_resource(unique_resource_name): continue owner_list = res_map[unique_resource_name][OWNERS] resource_config = res_map[unique_resource_name][CONF] visible_res_name = res_map[unique_resource_name][RESID] if client_id in owner_list: quick_res[unique_resource_name] = { "object_type": "multilinkline", "links": [ { "object_type": "link", "destination": "?unique_resource_name=%s" % unique_resource_name, "class": "adminlink", "title": "Manage %s" % unique_resource_name, "text": "Manage %s" % unique_resource_name, }, { "object_type": "link", "destination": "viewres.py?unique_resource_name=%s" % visible_res_name, "class": "infolink", "title": "View %s" % unique_resource_name, "text": "View %s" % unique_resource_name, }, ], } if unique_resource_name in unique_res_names: raw_conf_file = os.path.join(configuration.resource_home, unique_resource_name, "config.MiG") try: filehandle = open(raw_conf_file, "r") raw_conf = filehandle.readlines() filehandle.close() except: raw_conf = [""] res_html = display_resource( unique_resource_name, raw_conf, resource_config, owner_list, re_list, configuration ) output_objects.append({"object_type": "html_form", "text": res_html}) output_objects.append({"object_type": "sectionheader", "text": "Retire resource"}) output_objects.append( { "object_type": "text", "text": """ Use the link below to permanently remove the resource from the grid after stopping all units and the front end. """, } ) js_name = "delres%s" % hexlify(unique_resource_name) helper = html_post_helper(js_name, "delres.py", {"unique_resource_name": unique_resource_name}) output_objects.append({"object_type": "html_form", "text": helper}) output_objects.append( { "object_type": "link", "destination": "javascript: confirmDialog(%s, '%s');" % (js_name, "Really delete %s? (fails if it is busy)" % unique_resource_name), "class": "removelink", "title": "Delete %s" % unique_resource_name, "text": "Delete %s" % unique_resource_name, } ) owned += 1 if owned == 0: output_objects.append({"object_type": "text", "text": "You are not listed as owner of any resources!"}) else: sorted_links = quick_res.items() sorted_links.sort() for (res_id, link_obj) in sorted_links: quick_links.append(link_obj) # add new line quick_links.append({"object_type": "text", "text": ""}) quick_links.append({"object_type": "html_form", "text": '</div><div class="quicklinks">'}) quick_links.append( { "object_type": "link", "destination": "javascript:toggleHidden('.quicklinks');", "class": "additemlink", "title": "Toggle view", "text": "Show quick links", } ) quick_links.append({"object_type": "html_form", "text": "</div>"}) output_objects = output_objects[:quick_links_index] + quick_links + output_objects[quick_links_index:] return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) client_dir = client_id_dir(client_id) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) job_ids = accepted['job_id'] action = accepted['action'][-1] src = accepted['src'] dst = accepted['dst'][-1] title_entry = find_entry(output_objects, 'title') title_entry['text'] = '%s live I/O' % configuration.short_title output_objects.append({'object_type': 'header', 'text' : 'Request live communication with jobs'}) if not action in valid_actions: output_objects.append({'object_type': 'error_text', 'text' : 'Invalid action "%s" (supported: %s)' % \ (action, ', '.join(valid_actions))}) return (output_objects, returnvalues.CLIENT_ERROR) if action in post_actions and not correct_handler('POST'): output_objects.append( {'object_type': 'error_text', 'text' : 'Only accepting POST requests to prevent unintended updates'}) return (output_objects, returnvalues.CLIENT_ERROR) if not job_ids or action in interactive_actions: job_id = '' if job_ids: job_id = job_ids[-1] output_objects.append({'object_type': 'text', 'text' : ''' Fill in the live I/O details below to request communication with a running job. Job ID can be a full ID or a wild card pattern using "*" and "?" to match one or more of your job IDs. Use send output without source and destination paths to request upload of the default stdio files from the job on the resource to the associated job_output directory in your MiG home. Destination is a always handled as a directory path to put source files into. Source and destination paths are always taken relative to the job execution directory on the resource and your MiG home respectively. '''}) html = ''' <table class="liveio"> <tr> <td> <form method="post" action="liveio.py"> <table class="liveio"> <tr><td class=centertext> </td></tr> <tr><td> Action:<br /> <input type=radio name=action checked value="send" />send output <input type=radio name=action value="get" />get input </td></tr> <tr><td> Job ID:<br /> <input type=text size=60 name=job_id value="%s" /> </td></tr> <tr><td> Source path(s):<br /> <div id="srcfields"> <input type=text size=60 name=src value="" /><br /> </div> </td></tr> <tr><td> Destination path:<br /> <input type=text size=60 name=dst value="" /> </td></tr> <tr><td> <input type="submit" value="Send request" /> </td></tr> </table> </form> </td> <td> <script type="text/javascript"> fields = 1; max_fields = 64; function addInput() { if (fields < max_fields) { document.getElementById("srcfields").innerHTML += "<input type=text size=60 name=src value='' /><br />"; fields += 1; } else { alert("Maximum " + max_fields + " source fields allowed!"); document.form.add.disabled=true; } } </script> <form name="addsrcform"> <input type="button" onclick="addInput(); return false;" name="add" value="Add another source field" /> </form> </td> </tr> </table> ''' % job_id output_objects.append({'object_type': 'html_form', 'text' : html}) output_objects.append({'object_type': 'text', 'text': ''' Further live job control is avalable through your personal message queues. They provide a basic interface for centrally storing messages under your grid account and can be used to pass messages between jobs or for orchestrating jobs before and during execution. ''' }) output_objects.append({'object_type': 'link', 'destination': 'mqueue.py', 'text': 'Message queue interface'}) return (output_objects, returnvalues.OK) elif action in ['get', 'receive', 'input']: action = 'get' action_desc = 'will be downloaded to the job on the resource' elif action in ['put', 'send', 'output']: action = 'send' action_desc = 'will be uploaded from the job on the resource' else: output_objects.append({'object_type': 'error_text', 'text' : 'Invalid live io action: %s' % action}) return (output_objects, returnvalues.CLIENT_ERROR) output_objects.append({'object_type': 'text', 'text' : 'Requesting live I/O for %s' % ', '.join(job_ids)}) if action == 'get' and (not src or not dst): output_objects.append( {'object_type': 'error_text', 'text': 'src and dst parameters required for live input'}) return (output_objects, returnvalues.CLIENT_ERROR) # Automatic fall back to stdio files if output with no path provided if src: src_text = 'The files ' + ' '.join(src) else: src_text = 'The job stdio files' if dst: dst_text = 'the ' + dst + ' directory' else: dst_text = 'the corresponding job_output directory' # Please note that base_dir must end in slash to avoid access to other # user dirs when own name is a prefix of another user name base_dir = \ os.path.abspath(os.path.join(configuration.mrsl_files_dir, client_dir)) + os.sep filelist = [] for job_id in job_ids: job_id = job_id.strip() # is job currently being executed? # Backward compatibility - all_jobs keyword should match all jobs if job_id == all_jobs: job_id = '*' # Check directory traversal attempts before actual handling to avoid # leaking information about file system layout while allowing # consistent error messages unfiltered_match = glob.glob(base_dir + job_id + '.mRSL') match = [] for server_path in unfiltered_match: real_path = os.path.abspath(server_path) if not valid_user_path(real_path, base_dir, True): # out of bounds - save user warning for later to allow # partial match: # ../*/* is technically allowed to match own files. logger.warning("%s tried to %s restricted path %s ! (%s)" % \ (client_id, op_name, real_path, job_id)) continue # Insert valid job files in filelist for later treatment match.append(real_path) # Now actually treat list of allowed matchings and notify if no # (allowed) match.... if not match: output_objects.append( {'object_type': 'error_text', 'text' : '%s: You do not have any matching job IDs!' % job_id}) else: filelist += match for filepath in filelist: # Extract jo_id from filepath (replace doesn't modify filepath) mrsl_file = filepath.replace(base_dir, '') job_id = mrsl_file.replace('.mRSL', '') job_dict = unpickle(filepath, logger) if not job_dict: status = returnvalues.CLIENT_ERROR output_objects.append( {'object_type': 'error_text', 'text' : ('You can only list status of your own jobs. ' 'Please verify that you submitted the mRSL file ' 'with job id "%s" (Could not unpickle mRSL file %s)' ) % (job_id, filepath)}) continue if job_dict['STATUS'] != 'EXECUTING': output_objects.append( {'object_type': 'text', 'text' : 'Job %s is not currently being executed! Job status: %s' % (job_id, job_dict['STATUS'])}) continue if job_dict['UNIQUE_RESOURCE_NAME'] == 'ARC': output_objects.append( {'object_type': 'text', 'text' : 'Job %s is submitted to ARC, details are not available!' % job_id }) continue last_live_update_dict = {} last_live_update_file = configuration.mig_system_files + os.sep\ + job_id + '.last_live_update' if os.path.isfile(last_live_update_file): last_live_update_dict_unpickled = \ unpickle(last_live_update_file, logger) if not last_live_update_dict_unpickled: output_objects.append({'object_type': 'error_text', 'text' : 'Could not unpickle %s - skipping request!' % last_live_update_file}) continue if not last_live_update_dict_unpickled.has_key( 'LAST_LIVE_UPDATE_REQUEST_TIMESTAMP'): output_objects.append( {'object_type': 'error_text', 'text': 'Could not find needed key in %s.' % last_live_update_file}) continue last_live_update_request = \ last_live_update_dict_unpickled['LAST_LIVE_UPDATE_REQUEST_TIMESTAMP' ] difference = datetime.datetime.now()- last_live_update_request try: min_delay = \ int(configuration.min_seconds_between_live_update_requests) except: min_delay = 30 if difference.seconds < min_delay: output_objects.append( {'object_type': 'error_text', 'text': ('Request not allowed, you must wait at least ' \ '%s seconds between live update requests!' ) % min_delay}) continue # save this request to file to avoid DoS from a client request loop. last_live_update_dict['LAST_LIVE_UPDATE_REQUEST_TIMESTAMP'] = \ datetime.datetime.now() pickle_ret = pickle(last_live_update_dict, last_live_update_file, logger) if not pickle_ret: output_objects.append( {'object_type': 'error_text', 'text' : 'Error saving live io request timestamp to last_live_update ' 'file, request not sent!'}) continue # # # ## job is being executed right now, send live io request to frontend # # # get resource_config, needed by scp_file_to_resource #(status, resource_config) = get_resource_configuration( # resource_home, unique_resource_name, logger) resource_config = job_dict['RESOURCE_CONFIG'] (status, exe) = get_resource_exe(resource_config, job_dict['EXE'], logger) if not status: output_objects.append( {'object_type': 'error_text', 'text' : 'Could not get exe configuration for job %s' % job_id}) continue local_file = '%s.%supdate' % (job_dict['LOCALJOBNAME'], action) if not os.path.exists(local_file): # create try: filehandle = open(local_file, 'w') filehandle.write('job_id ' + job_dict['JOB_ID'] + '\n') filehandle.write('localjobname ' + job_dict['LOCALJOBNAME'] + '\n') filehandle.write('execution_user ' + exe['execution_user'] + '\n') filehandle.write('execution_node ' + exe['execution_node'] + '\n') filehandle.write('execution_dir ' + exe['execution_dir'] + '\n') filehandle.write('target liveio\n') # Leave defaults src and dst to FE script if not provided if src: filehandle.write('source ' + ' '.join(src) + '\n') if dst: filehandle.write('destination ' + dst + '\n') # Backward compatible test for shared_fs - fall back to scp if exe.has_key('shared_fs') and exe['shared_fs']: filehandle.write('copy_command cp\n') filehandle.write('copy_frontend_prefix \n') filehandle.write('copy_execution_prefix \n') else: filehandle.write('copy_command scp -B\n') filehandle.write('copy_frontend_prefix ${frontend_user}@${frontend_node}:\n' ) filehandle.write('copy_execution_prefix ${execution_user}@${execution_node}:\n' ) filehandle.write('### END OF SCRIPT ###\n') filehandle.close() except Exception, exc: pass if not os.path.exists(local_file): output_objects.append( {'object_type': 'error_text', 'text' : '.%supdate file not available on %s server' % \ (action, configuration.short_title)}) continue scpstatus = copy_file_to_resource(local_file, '%s.%supdate' % (job_dict['LOCALJOBNAME'], action), resource_config, logger) if not scpstatus: output_objects.append( {'object_type': 'error_text', 'text' : 'Error sending request for live io to resource!'}) continue else: output_objects.append( {'object_type': 'text', 'text' : 'Request for live io was successfully sent to the resource!' }) output_objects.append( {'object_type': 'text', 'text' : '%s %s and should become available in %s in a minute.' % \ (src_text, action_desc, dst_text) }) if action == 'send': if not dst: target_path = '%s/%s/*' % (job_output_dir, job_id) else: target_path = dst output_objects.append({'object_type': 'link', 'destination' : 'ls.py?path=%s' % target_path, 'text': 'View uploaded files'}) else: output_objects.append({'object_type': 'link', 'destination' : 'ls.py?path=%s' % ';path='.join(src), 'text': 'View files for download'}) try: os.remove(local_file) except Exception, exc: pass
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Delete frozen archive' defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) if not correct_handler('POST'): output_objects.append( {'object_type': 'error_text', 'text' : 'Only accepting POST requests to prevent unintended updates'}) return (output_objects, returnvalues.CLIENT_ERROR) flavor = accepted['flavor'][-1] if not flavor in freeze_flavors.keys(): output_objects.append({'object_type': 'error_text', 'text': 'Invalid freeze flavor: %s' % flavor}) return (output_objects, returnvalues.CLIENT_ERROR) title = freeze_flavors[flavor]['deletefreeze_title'] output_objects.append({'object_type': 'header', 'text': title}) title_entry = find_entry(output_objects, 'title') title_entry['text'] = title if not configuration.site_enable_freeze: output_objects.append({'object_type': 'text', 'text': '''Freezing archives is disabled on this site. Please contact the Grid admins %s if you think it should be enabled. ''' % configuration.admin_email}) return (output_objects, returnvalues.OK) freeze_id = accepted['freeze_id'][-1] # NB: the restrictions on freeze_id prevents illegal directory traversal if not is_frozen_archive(freeze_id, configuration): logger.error("%s: invalid freeze '%s': %s" % (op_name, client_id, freeze_id)) output_objects.append({'object_type': 'error_text', 'text': "No such frozen archive: '%s'" % freeze_id}) return (output_objects, returnvalues.CLIENT_ERROR) (load_status, freeze_dict) = get_frozen_archive(freeze_id, configuration) if not load_status: logger.error("%s: load failed for '%s': %s" % \ (op_name, freeze_id, freeze_dict)) output_objects.append( {'object_type': 'error_text', 'text': 'Could not read frozen archive details for %s' % freeze_id}) return (output_objects, returnvalues.SYSTEM_ERROR) # Prevent easy delete if the frozen archive if configuration forbids it if configuration.site_permanent_freeze: output_objects.append( {'object_type': 'error_text', 'text': "Can't delete frozen archive '%s' yourself due to site policy" % freeze_id}) return (output_objects, returnvalues.CLIENT_ERROR) # Make sure the frozen archive belongs to the user trying to delete it if client_id != freeze_dict['CREATOR']: logger.error("%s: illegal access attempt for '%s': %s" % \ (op_name, freeze_id, client_id)) output_objects.append({'object_type': 'error_text', 'text': \ 'You are not the owner of frozen archive "%s"' % freeze_id}) return (output_objects, returnvalues.CLIENT_ERROR) if freeze_dict.get('FLAVOR','freeze') != flavor: logger.error("%s: flavor mismatch for '%s': %s vs %s" % \ (op_name, freeze_id, flavor, freeze_dict)) output_objects.append({'object_type': 'error_text', 'text' : 'No such %s archive "%s"' % (flavor, freeze_id)}) return (output_objects, returnvalues.CLIENT_ERROR) # Delete the frozen archive (status, msg) = delete_frozen_archive(freeze_id, configuration) # If something goes wrong when trying to delete frozen archive # freeze_id, an error is displayed. if not status: logger.error("%s: failed for '%s': %s" % (op_name, freeze_id, msg)) output_objects.append({'object_type': 'error_text', 'text' : 'Could not remove %s frozen archive: %s' % (freeze_id, msg)}) return (output_objects, returnvalues.SYSTEM_ERROR) # If deletion of frozen archive freeze_id is successful, we just # return OK else: logger.info("%s: successful for '%s': %s" % (op_name, freeze_id, client_id)) output_objects.append( {'object_type': 'text', 'text' : 'Successfully deleted frozen archive: "%s"' % freeze_id}) output_objects.append({'object_type': 'link', 'destination': 'freezedb.py', 'class': 'infolink', 'title': 'Show frozen archives', 'text': 'Show frozen archives'}) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = initialize_main_variables(client_id, op_header=False) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) meta = ( """<meta http-equiv="refresh" content="%s" /> """ % configuration.sleep_secs ) style = themed_styles(configuration) script = """ <script type="text/javascript" src="/images/js/jquery.js"></script> <script type="text/javascript" src="/images/js/jquery.tablesorter.js"></script> <script type="text/javascript" > $(document).ready(function() { // table initially sorted by col. 1 (name) var sortOrder = [[1,0]]; // use image path for sorting if there is any inside var imgTitle = function(contents) { var key = $(contents).find("a").attr("class"); if (key == null) { key = $(contents).html(); } return key; } $("table.monitor").tablesorter({widgets: ["zebra"], textExtraction: imgTitle, }); $("table.monitor").each(function () { try { $(this).trigger("sorton", [sortOrder]); } catch(err) { /* tablesorter chokes on empty tables - just continue */ } }); } ); </script> """ title_entry = find_entry(output_objects, "title") title_entry["text"] = "%s Monitor" % configuration.short_title title_entry["meta"] = meta title_entry["style"] = style title_entry["javascript"] = script allowed_vgrids = user_allowed_vgrids(configuration, client_id) vgrid_list = accepted["vgrid_name"] if all_vgrids in accepted["vgrid_name"]: vgrid_list = [i for i in vgrid_list if all_vgrids != i] + allowed_vgrids # Force list to sequence of unique entries for vgrid_name in set(vgrid_list): html = "" if not vgrid_is_owner_or_member(vgrid_name, client_id, configuration): output_objects.append( { "object_type": "error_text", "text": """You must be an owner or member of %s %s to access the monitor.""" % (vgrid_name, configuration.site_vgrid_label), } ) return (output_objects, returnvalues.CLIENT_ERROR) monitor_file = os.path.join(configuration.vgrid_home, vgrid_name, "%s.html" % configuration.vgrid_monitor) try: monitor_fd = open(monitor_file, "r") past_header = False for line in monitor_fd: if -1 != line.find("end of raw header"): past_header = True continue if not past_header: continue if -1 != line.find("begin raw footer:"): break html += str(line) monitor_fd.close() except Exception, exc: output_objects.append( { "object_type": "error_text", "text": "Error reading %s monitor page (%s)" % (configuration.site_vgrid_label, exc), } ) return (output_objects, returnvalues.SYSTEM_ERROR) output_objects.append({"object_type": "html_form", "text": html})
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False, op_menu=False) client_dir = client_id_dir(client_id) defaults = signature()[1] (validate_status, accepted) = validate_input(user_arguments_dict, defaults, output_objects, allow_rejects=False) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) title_entry = find_entry(output_objects, 'title') title_entry['text'] = '%s certificate request' % configuration.short_title title_entry['skipmenu'] = True form_fields = ['full_name', 'organization', 'email', 'country', 'state', 'password', 'verifypassword', 'comment'] title_entry['style'] = themed_styles(configuration) title_entry['javascript'] = cert_js_helpers(form_fields) output_objects.append({'object_type': 'html_form', 'text':''' <div id="contextual_help"> <div class="help_gfx_bubble"><!-- graphically connect field with help text --></div> <div class="help_message"><!-- filled by js --></div> </div> ''' }) header_entry = {'object_type': 'header', 'text' : 'Welcome to the %s certificate request page' % \ configuration.short_title} output_objects.append(header_entry) # Please note that base_dir must end in slash to avoid access to other # user dirs when own name is a prefix of another user name base_dir = os.path.abspath(os.path.join(configuration.user_home, client_dir)) + os.sep user_fields = {'full_name': '', 'organization': '', 'email': '', 'state': '', 'country': '', 'password': '', 'verifypassword': ''} if not os.path.isdir(base_dir) and client_id: # Redirect to extcert page with certificate requirement but without # changing access method (CGI vs. WSGI). extcert_url = os.environ['REQUEST_URI'].replace('-sid', '-bin') extcert_url = os.path.join(os.path.dirname(extcert_url), 'extcert.py') extcert_link = {'object_type': 'link', 'destination': extcert_url, 'text': 'Sign up with existing certificate (%s)' % client_id} output_objects.append({'object_type': 'warning', 'text' : 'Apparently you already have a suitable %s certificate that you may sign up with:' % \ configuration.short_title }) output_objects.append(extcert_link) output_objects.append({'object_type': 'warning', 'text' : 'However, if you want a dedicated %s certificate you can still request one below:' % \ configuration.short_title }) elif client_id: for entry in (title_entry, header_entry): entry['text'] = entry['text'].replace('request', 'request / renew') output_objects.append({'object_type': 'html_form', 'text' : '''<p> Apparently you already have a valid %s certificate, but if it is about to expire you can renew it by posting the form below. Renewal with changed fields is <span class=mandatory>not</span> supported, so all fields including your original password must remain unchanged for renew to work. Otherwise it results in a request for a new account and certificate without access to your old files, jobs and privileges.</p>''' % \ configuration.short_title}) user_fields.update(distinguished_name_to_user(client_id)) user_fields.update({ 'valid_name_chars': html_escape(valid_name_chars), 'valid_password_chars': html_escape(valid_password_chars), 'password_min_len': password_min_len, 'password_max_len': password_max_len, 'site': configuration.short_title }) output_objects.append({'object_type': 'html_form', 'text' : """ Please enter your information in at least the <span class=mandatory>mandatory</span> fields below and press the Send button to submit the certificate request to the %(site)s administrators. <p class='criticaltext highlight_message'> IMPORTANT: Please help us verify your identity by providing Organization and Email data that we can easily validate!<br /> That is, if You're a student/employee at KU, please enter institute acronym (NBI, DIKU, etc.) in the Organization field and use your corresponding [email protected] or USER@*.ku.dk address in the Email field. </p> <hr /> <div class=form_container> <!-- use post here to avoid field contents in URL --> <form method=post action=reqcertaction.py onSubmit='return validate_form();'> <table> <tr><td class='mandatory label'>Full name</td><td><input id='full_name_field' type=text name=cert_name value='%(full_name)s' /></td><td class=fill_space><br /></td></tr> <tr><td class='mandatory label'>Email address</td><td><input id='email_field' type=text name=email value='%(email)s' /> </td><td class=fill_space><br /></td></tr> <tr><td class='mandatory label'>Organization</td><td><input id='organization_field' type=text name=org value='%(organization)s' /></td><td class=fill_space><br /></td></tr> <tr><td class='mandatory label'>Two letter country-code</td><td><input id='country_field' type=text name=country maxlength=2 value='%(country)s' /></td><td class=fill_space><br /></td></tr> <tr><td class='optional label'>State</td><td><input id='state_field' type=text name=state value='%(state)s' /> </td><td class=fill_space><br /></td></tr> <tr><td class='mandatory label'>Password</td><td><input id='password_field' type=password name=password maxlength=%(password_max_len)s value='%(password)s' /> </td><td class=fill_space><br /></td></tr> <tr><td class='mandatory label'>Verify password</td><td><input id='verifypassword_field' type=password name=verifypassword maxlength=%(password_max_len)s value='%(verifypassword)s' /></td><td class=fill_space><br /></td></tr> <tr><td class='optional label'>Optional comment or reason why you should<br />be granted a %(site)s certificate:</td><td><textarea id='comment_field' rows=4 name=comment></textarea></td><td class=fill_space><br /></td></tr> <tr><td class='label'><!-- empty area --></td><td><input id='submit_button' type=submit value=Send /></td><td class=fill_space><br /></td></tr> </table> </form> </div> <hr /> <br /> <div class='warn_message'>Please note that passwords may be accessible to the %(site)s administrators!</div> <br /> <!-- Hidden help text --> <div id='help_text'> <div id='full_name_help'>Your full name, restricted to the characters in '%(valid_name_chars)s'</div> <div id='organization_help'>Organization name or acronym matching email</div> <div id='email_help'>Email address associated with your organization if at all possible</div> <div id='country_help'>Country code of your organization and on the form DE/DK/GB/US/.. , <a href='http://www.iso.org/iso/country_codes/iso_3166_code_lists/country_names_and_code_elements.html'>help</a></div> <div id='state_help'>Optional state of your organization, please just leave empty unless it is in the US or similar</div> <div id='password_help'>Password is restricted to the characters in '%(valid_password_chars)s and must be %(password_min_len)s to %(password_max_len)s characters long'</div> <div id='verifypassword_help'>Please repeat password</div> <div id='comment_help'>Optional, but a short informative comment may help us verify your certificate needs and thus speed up our response.</div> </div> """ % user_fields}) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False, op_menu=False) defaults = signature()[1] logger.debug('in extoidaction: %s' % user_arguments_dict) (validate_status, accepted) = validate_input(user_arguments_dict, defaults, output_objects, allow_rejects=False) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) # Unfortunately OpenID does not use POST #if not safe_handler(configuration, 'post', op_name, client_id, # get_csrf_limit(configuration), accepted): # output_objects.append( # {'object_type': 'error_text', 'text': '''Only accepting #CSRF-filtered POST requests to prevent unintended updates''' # }) # return (output_objects, returnvalues.CLIENT_ERROR) title_entry = find_entry(output_objects, 'title') title_entry['text'] = '%s OpenID account sign up' % configuration.short_title title_entry['skipmenu'] = True output_objects.append({'object_type': 'header', 'text' : '%s OpenID account sign up' % \ configuration.short_title }) admin_email = configuration.admin_email smtp_server = configuration.smtp_server user_pending = os.path.abspath(configuration.user_pending) # force name to capitalized form (henrik karlsen -> Henrik Karlsen) id_url = os.environ['REMOTE_USER'].strip() openid_prefix = configuration.user_ext_oid_provider.rstrip('/') + '/' raw_login = id_url.replace(openid_prefix, '') full_name = accepted['openid.sreg.full_name'][-1].strip().title() country = accepted['openid.sreg.country'][-1].strip().upper() state = accepted['state'][-1].strip().title() organization = accepted['openid.sreg.organization'][-1].strip() organizational_unit = accepted['openid.sreg.organizational_unit'][-1].strip() locality = accepted['openid.sreg.locality'][-1].strip() # lower case email address email = accepted['openid.sreg.email'][-1].strip().lower() password = accepted['password'][-1] #verifypassword = accepted['verifypassword'][-1] # keep comment to a single line comment = accepted['comment'][-1].replace('\n', ' ') # single quotes break command line format - remove comment = comment.replace("'", ' ') user_dict = { 'full_name': full_name, 'organization': organization, 'organizational_unit': organizational_unit, 'locality': locality, 'state': state, 'country': country, 'email': email, 'password': password, 'comment': comment, 'expire': int(time.time() + oid_valid_days * 24 * 60 * 60), 'openid_names': [raw_login], 'auth': ['extoid'], } fill_distinguished_name(user_dict) user_id = user_dict['distinguished_name'] if configuration.user_openid_providers and configuration.user_openid_alias: user_dict['openid_names'].append( user_dict[configuration.user_openid_alias]) req_path = None try: (os_fd, req_path) = tempfile.mkstemp(dir=user_pending) os.write(os_fd, dumps(user_dict)) os.close(os_fd) except Exception, err: logger.error('Failed to write OpenID account request to %s: %s' % (req_path, err)) output_objects.append({'object_type': 'error_text', 'text' : 'Request could not be sent to grid administrators. Please contact them manually on %s if this error persists.' % admin_email}) return (output_objects, returnvalues.SYSTEM_ERROR)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Delete runtime environment' output_objects.append({'object_type': 'header', 'text' : 'Delete runtime environment'}) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) if not correct_handler('POST'): output_objects.append( {'object_type': 'error_text', 'text' : 'Only accepting POST requests to prevent unintended updates'}) return (output_objects, returnvalues.CLIENT_ERROR) re_name = accepted['re_name'][-1] if not valid_dir_input(configuration.re_home, re_name): logger.warning( "possible illegal directory traversal attempt re_name '%s'" % re_name) output_objects.append({'object_type': 'error_text', 'text' : 'Illegal runtime environment name: "%s"' % re_name}) return (output_objects, returnvalues.CLIENT_ERROR) # Check whether re_name represents a runtime environment if not is_runtime_environment(re_name, configuration): output_objects.append({'object_type': 'error_text', 'text': "No such runtime environment: '%s'" % re_name}) return (output_objects, returnvalues.CLIENT_ERROR) re_dict = get_re_dict(re_name, configuration) if not re_dict[0]: output_objects.append( {'object_type': 'error_text', 'text': 'Could not read runtime environment details for %s' % re_name}) return (output_objects, returnvalues.SYSTEM_ERROR) # Make sure the runtime environment belongs to the user trying to delete it if client_id != re_dict[0]['CREATOR']: output_objects.append({'object_type': 'error_text', 'text': \ 'You are not the owner of runtime environment "%s"' % re_name}) return (output_objects, returnvalues.CLIENT_ERROR) # Prevent delete if the runtime environment is used by any resources actives = resources_using_re(configuration, re_name) # If the runtime environment is active, an error message is printed, along # with a list of the resources using the runtime environment if actives: output_objects.append( {'object_type': 'error_text', 'text': "Can't delete runtime environment '%s' in use by resources:" % re_name}) output_objects.append({'object_type': 'list', 'list' : actives}) output_objects.append({'object_type': 'link', 'destination': 'redb.py', 'class': 'infolink', 'title': 'Show runtime environments', 'text': 'Show runtime environments'}) return (output_objects, returnvalues.CLIENT_ERROR) # Delete the runtime environment (status, msg) = delete_runtimeenv(re_name, configuration) # If something goes wrong when trying to delete runtime environment # re_name, an error is displayed. if not status: output_objects.append({'object_type': 'error_text', 'text' : 'Could not remove %s runtime environment: %s' % (re_name, msg)}) return (output_objects, returnvalues.SYSTEM_ERROR) # If deletion of runtime environment re_name is successful, we just # return OK else: output_objects.append( {'object_type': 'text', 'text' : 'Successfully deleted runtime environment: "%s"' % re_name}) output_objects.append({'object_type': 'link', 'destination': 'redb.py', 'class': 'infolink', 'title': 'Show runtime environments', 'text': 'Show runtime environments'}) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, require_user=False ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) title_entry = find_entry(output_objects, 'title') title_entry['text'] = '%s certificate sign up' % configuration.short_title title_entry['skipmenu'] = True form_fields = ['cert_id', 'cert_name', 'organization', 'email', 'country', 'state', 'comment'] title_entry['style'] = themed_styles(configuration) title_entry['javascript'] = cert_js_helpers(form_fields) output_objects.append({'object_type': 'html_form', 'text':''' <div id="contextual_help"> <div class="help_gfx_bubble"><!-- graphically connect field with help text--></div> <div class="help_message"><!-- filled by js --></div> </div> ''' }) header_entry = {'object_type': 'header', 'text' : 'Welcome to the %s certificate sign up page' % \ configuration.short_title} output_objects.append(header_entry) # Redirect to reqcert page without certificate requirement but without # changing access method (CGI vs. WSGI). certreq_url = os.environ['REQUEST_URI'].replace('-bin', '-sid') certreq_url = os.path.join(os.path.dirname(certreq_url), 'reqcert.py') certreq_link = {'object_type': 'link', 'destination': certreq_url, 'text': 'Request a new %s certificate' % \ configuration.short_title } new_user = distinguished_name_to_user(client_id) # If cert auto create is on, add user without admin interaction if configuration.auto_add_cert_user == False: extcertaction = 'extcertaction.py' else: extcertaction = 'autocreate.py' output_objects.append({'object_type': 'html_form', 'text' : """ This page is used to sign up for %(site)s with an existing certificate from a Certificate Authority (CA) allowed for %(site)s. You can use it if you already have a x509 certificate from another accepted CA. In this way you can simply use your existing certificate for %(site)s access instead of requesting a new one. <br /> The page tries to auto load any certificate your browser provides and fill in the fields accordingly, but in case it can't guess all <span class=mandatory>mandatory</span> fields, you still need to fill in those.<br /> Please enter any missing information below and press the Send button to submit the external certificate sign up request to the %(site)s administrators. <p class='criticaltext highlight_message'>IMPORTANT: Please help us verify your identity by providing Organization and Email data that we can easily validate!<br /> That is, if You're a student/employee at KU, please enter institute acronym (NBI, DIKU, etc.) in the Organization field and use your corresponding [email protected] or USER@*.ku.dk address in the Email field.</p> <hr /> <div class=form_container> <!-- use post here to avoid field contents in URL --> <form method=post action=%(extcertaction)s onSubmit='return validate_form();'> <table> <tr><td class='mandatory label'>Certificate DN</td><td><input id='cert_id_field' type=text size=%(dn_max_len)s maxlength=%(dn_max_len)s name=cert_id value='%(client_id)s' /></td><td class=fill_space></td></tr> <tr><td class='mandatory label'>Full name</td><td><input id='cert_name_field' type=text name=cert_name value='%(common_name)s' /></td><td class=fill_space></td></tr> <tr><td class='mandatory label'>Email address</td><td><input id='email_field' type=text name=email value='%(email)s' /></td><td class=fill_space></td></tr> <tr><td class='mandatory label'>Organization</td><td><input id='organization_field' type=text name=org value='%(org)s' /></td><td class=fill_space></td></tr> <tr><td class='mandatory label'>Two letter country-code</td><td><input id='country_field' type=text name=country maxlength=2 value='%(country)s' /></td><td class=fill_space></td></tr> <tr><td class='optional label'>State</td><td><input id='state_field' type=text name=state value='%(state)s' /></td><td class=fill_space></td></tr> <tr><td class='optional label'>Comment or reason why you should<br />be granted a %(site)s certificate:</td><td><textarea id='comment_field' rows=4 name=comment></textarea></td><td class=fill_space></td></tr> <tr><td class='label'><!-- empty area --></td><td><input id='submit_button' type='submit' value='Send' /></td><td class=fill_space></td></tr> </table> </form> </div> <!-- Hidden help text --> <div id='help_text'> <div id='cert_id_help'>Must be the exact Distinguished Name (DN) of your certificate</div> <div id='cert_name_help'>Your full name, restricted to the characters in '%(valid_name_chars)s'</div> <div id='organization_help'>Organization name or acronym matching email</div> <div id='email_help'>Email address associated with your organization if at all possible</div> <div id='country_help'>Country code of your organization and on the form DE/DK/GB/US/.. , <a href='http://www.iso.org/iso/country_codes/iso_3166_code_lists/country_names_and_code_elements.html'>help</a></div> <div id='state_help'>Optional state of your organization, please just leave empty unless it is in the US or similar</div> <div id='comment_help'>Optional, but a short informative comment may help us verify your certificate needs and thus speed up our response.</div> </div> """ % { 'extcertaction': extcertaction, 'valid_name_chars': valid_name_chars, 'client_id': client_id, 'dn_max_len': dn_max_len, 'common_name': new_user.get('full_name', ''), 'org': new_user.get('organization', ''), 'email': new_user.get('email', ''), 'state': new_user.get('state', ''), 'country': new_user.get('country', ''), 'site': configuration.short_title, }}) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = initialize_main_variables( client_id, op_header=False, op_menu=False ) defaults = signature()[1] logger.debug("in extoidaction: %s" % user_arguments_dict) (validate_status, accepted) = validate_input(user_arguments_dict, defaults, output_objects, allow_rejects=False) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) # Unfortunately OpenID does not use POST # if not correct_handler('GET'): # output_objects.append( # {'object_type': 'error_text', 'text' # : 'Only accepting POST requests to prevent unintended updates'}) # return (output_objects, returnvalues.CLIENT_ERROR) title_entry = find_entry(output_objects, "title") title_entry["text"] = "%s OpenID sign up" % configuration.short_title title_entry["skipmenu"] = True output_objects.append({"object_type": "header", "text": "%s OpenID sign up" % configuration.short_title}) admin_email = configuration.admin_email smtp_server = configuration.smtp_server user_pending = os.path.abspath(configuration.user_pending) # force name to capitalized form (henrik karlsen -> Henrik Karlsen) id_url = os.environ["REMOTE_USER"].strip() openid_prefix = configuration.user_openid_providers[0].rstrip("/") + "/" raw_login = id_url.replace(openid_prefix, "") full_name = accepted["openid.sreg.full_name"][-1].strip().title() country = accepted["openid.sreg.country"][-1].strip().upper() state = accepted["state"][-1].strip().title() organization = accepted["openid.sreg.organization"][-1].strip() organizational_unit = accepted["openid.sreg.organizational_unit"][-1].strip() locality = accepted["openid.sreg.locality"][-1].strip() # lower case email address email = accepted["openid.sreg.email"][-1].strip().lower() password = accepted["password"][-1] # verifypassword = accepted['verifypassword'][-1] # keep comment to a single line comment = accepted["comment"][-1].replace("\n", " ") # single quotes break command line format - remove comment = comment.replace("'", " ") user_dict = { "full_name": full_name, "organization": organization, "organizational_unit": organizational_unit, "locality": locality, "state": state, "country": country, "email": email, "password": password, "comment": comment, "expire": int(time.time() + oid_valid_days * 24 * 60 * 60), "openid_names": [raw_login], } fill_distinguished_name(user_dict) user_id = user_dict["distinguished_name"] if configuration.user_openid_providers and configuration.user_openid_alias: user_dict["openid_names"].append(user_dict[configuration.user_openid_alias]) req_path = None try: (os_fd, req_path) = tempfile.mkstemp(dir=user_pending) os.write(os_fd, dumps(user_dict)) os.close(os_fd) except Exception, err: logger.error("Failed to write certificate request to %s: %s" % (req_path, err)) output_objects.append( { "object_type": "error_text", "text": "Request could not be sent to grid administrators. Please contact them manually on %s if this error persists." % admin_email, } ) return (output_objects, returnvalues.SYSTEM_ERROR)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) status = returnvalues.OK defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Manage jobs' output_objects.append({'object_type': 'header', 'text' : 'Manage Jobs'}) output_objects.append({'object_type': 'sectionheader', 'text' : 'View status of all submitted jobs'}) output_objects.append({'object_type': 'html_form', 'text' : """ <form method="post" action="jobstatus.py"> Sort by modification time: <input type="radio" name="flags" value="sv" />yes <input type="radio" name="flags" checked="checked" value="vi" />no<br /> <input type="hidden" name="job_id" value="*" /> <input type="hidden" name="output_format" value="html" /> <input type="submit" value="Show All" /> </form> """}) output_objects.append({'object_type': 'sectionheader', 'text' : 'View status of individual jobs'}) output_objects.append({'object_type': 'html_form', 'text' : """ Filter job IDs (* and ? wildcards are supported)<br /> <form method="post" action="jobstatus.py"> Job ID: <input type="text" name="job_id" value="*" size="30" /><br /> Show only <input type="text" name="max_jobs" size="6" value=5 /> first matching jobs<br /> Sort by modification time: <input type="radio" name="flags" checked="checked" value="vsi" />yes <input type="radio" name="flags" value="vi" />no<br /> <input type="hidden" name="output_format" value="html" /> <input type="submit" value="Show" /> </form> """}) output_objects.append({'object_type': 'sectionheader', 'text' : 'Resubmit job'}) output_objects.append({'object_type': 'html_form', 'text' : """ <form method="post" action="resubmit.py"> Job ID: <input type="text" name="job_id" size="30" /><br /> <input type="hidden" name="output_format" value="html" /> <input type="submit" value="Submit" /> </form> """}) output_objects.append({'object_type': 'sectionheader', 'text' : 'Freeze pending job'}) output_objects.append({'object_type': 'html_form', 'text' : """ <form method="post" action="jobaction.py"> Job ID: <input type="text" name="job_id" size="30" /><br /> <input type="hidden" name="action" value="freeze" /> <input type="hidden" name="output_format" value="html" /> <input type="submit" value="Freeze job" /> </form> """}) output_objects.append({'object_type': 'sectionheader', 'text' : 'Thaw frozen job'}) output_objects.append({'object_type': 'html_form', 'text' : """ <form method="post" action="jobaction.py"> Job ID: <input type="text" name="job_id" size="30" /><br /> <input type="hidden" name="action" value="thaw" /> <input type="hidden" name="output_format" value="html" /> <input type="submit" value="Thaw job" /> </form> """}) output_objects.append({'object_type': 'sectionheader', 'text' : 'Cancel pending or executing job'}) output_objects.append({'object_type': 'html_form', 'text' : """ <form method="post" action="jobaction.py"> Job ID: <input type="text" name="job_id" size="30" /><br /> <input type="hidden" name="action" value="cancel" /> <input type="hidden" name="output_format" value="html" /> <input type="submit" value="Cancel job" /> </form> """}) output_objects.append({'object_type': 'sectionheader', 'text' : 'Request live I/O'}) output_objects.append({'object_type': 'html_form', 'text' : """ <form method="post" action="liveio.py"> Job ID: <input type="text" name="job_id" size="30" /><br /> <input type="hidden" name="output_format" value="html" /> <input type="submit" value="Request" /> </form> <br /> """}) return (output_objects, status)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) client_dir = client_id_dir(client_id) valid_langs = {'sh': 'shell', 'python': 'python'} valid_flavors = {'user': '******', 'resource': 'vgridscriptgen'} defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) if not correct_handler('POST'): output_objects.append( {'object_type': 'error_text', 'text' : 'Only accepting POST requests to prevent unintended updates'}) return (output_objects, returnvalues.CLIENT_ERROR) flags = ''.join(accepted['flags']) langs = accepted['lang'] flavor_list = accepted['flavor'] sh_cmd = accepted['sh_cmd'][-1] python_cmd = accepted['python_cmd'][-1] flavors = [] title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Script generator' output_objects.append({'object_type': 'header', 'text' : 'Script generator'}) status = returnvalues.OK # Please note that base_dir must end in slash to avoid access to other # user dirs when own name is a prefix of another user name base_dir = os.path.abspath(os.path.join(configuration.user_home, client_dir)) + os.sep if 'h' in flags: output_objects = usage(output_objects, valid_langs, valid_flavors) return (output_objects, status) # Filter out any invalid flavors to avoid illegal filenames, etc. for f in flavor_list: if f in valid_flavors.keys(): flavors.append(f) # Default to user scripts if not flavors: if flavor_list: output_objects.append({'object_type': 'text', 'text' : 'No valid flavors specified - falling back to user scripts' }) flavors = ['user'] # Generate scripts in a "unique" destination directory # gmtime([seconds]) -> (tm_year, tm_mon, tm_day, tm_hour, tm_min, # tm_sec, tm_wday, tm_yday, tm_isdst) now = time.gmtime() timestamp = '%.2d%.2d%.2d-%.2d%.2d%.2d' % ( now[2], now[1], now[0], now[3], now[4], now[5], ) if not langs: # Add new languages here languages = [(usergen.sh_lang, sh_cmd, usergen.sh_ext), (usergen.python_lang, python_cmd, usergen.python_ext)] else: languages = [] # check arguments for lang in langs: if lang == 'sh': interpreter = sh_cmd extension = usergen.sh_ext elif lang == 'python': interpreter = python_cmd extension = usergen.python_ext else: output_objects.append({'object_type': 'warning', 'text' : 'Unknown script language: %s - ignoring!' % lang}) continue languages.append((lang, interpreter, extension)) if not languages: output_objects.append({'object_type': 'error_text', 'text' : 'No valid languages specified - aborting script generation' }) return (output_objects, returnvalues.CLIENT_ERROR) for flavor in flavors: script_dir = '%s-%s-scripts-%s' % (configuration.short_title, flavor, timestamp) dest_dir = '%s%s' % (base_dir, script_dir) if not os.path.isdir(dest_dir): try: os.mkdir(dest_dir) except Exception, exc: output_objects.append({'object_type': 'error_text', 'text' : 'Failed to create destination directory (%s) - aborting script generation' % exc}) return (output_objects, returnvalues.SYSTEM_ERROR) for (lang, _, _) in languages: output_objects.append({'object_type': 'text', 'text' : 'Generating %s %s scripts in the %s subdirectory of your %s home directory' % (lang, flavor, script_dir, configuration.short_title )}) # Generate all scripts if flavor == 'user': for op in usergen.script_ops: generator = 'usergen.generate_%s' % op eval(generator)(languages, dest_dir) if usergen.shared_lib: usergen.generate_lib(usergen.script_ops, languages, dest_dir) if usergen.test_script: usergen.generate_test(languages, dest_dir) elif flavor == 'resource': for op in vgridgen.script_ops_single_arg: vgridgen.generate_single_argument(op[0], op[1], languages, dest_dir) for op in vgridgen.script_ops_single_upload_arg: vgridgen.generate_single_argument_upload(op[0], op[1], op[2], languages, dest_dir) for op in vgridgen.script_ops_two_args: vgridgen.generate_two_arguments(op[0], op[1], op[2], languages, dest_dir) for op in vgridgen.script_ops_ten_args: vgridgen.generate_ten_arguments(op[0], op[1], op[2], op[3], op[4], op[5], op[6], op[7], op[8], op[9], op[10], languages, dest_dir) else: output_objects.append({'object_type': 'warning_text', 'text' : 'Unknown flavor: %s' % flavor}) continue # Always include license conditions file usergen.write_license(dest_dir) output_objects.append({'object_type': 'text', 'text': '... Done' }) output_objects.append({'object_type': 'text', 'text' : '%s %s scripts are now available in your %s home directory:' % (configuration.short_title, flavor, configuration.short_title)}) output_objects.append({'object_type': 'link', 'text' : 'View directory', 'destination' : 'fileman.py?path=%s/' % script_dir}) # Create zip from generated dir output_objects.append({'object_type': 'text', 'text' : 'Generating zip archive of the %s %s scripts' % (configuration.short_title, flavor)}) script_zip = script_dir + '.zip' dest_zip = '%s%s' % (base_dir, script_zip) # Force compression zip_file = zipfile.ZipFile(dest_zip, 'w', zipfile.ZIP_DEFLATED) # Directory write is not supported - add each file manually for script in os.listdir(dest_dir): zip_file.write(dest_dir + os.sep + script, script_dir + os.sep + script) # Preserve executable flag in accordance with: # http://mail.python.org/pipermail/pythonmac-sig/2005-March/013491.html for zinfo in zip_file.filelist: zinfo.create_system = 3 zip_file.close() # Verify CRC zip_file = zipfile.ZipFile(dest_zip, 'r') err = zip_file.testzip() zip_file.close() if err: output_objects.append({'object_type': 'error_text', 'text' : 'Zip file integrity check failed! (%s)' % err}) status = returnvalues.SYSTEM_ERROR continue output_objects.append({'object_type': 'text', 'text': '... Done' }) output_objects.append({'object_type': 'text', 'text' : 'Zip archive of the %s %s scripts are now available in your %s home directory' % (configuration.short_title, flavor, configuration.short_title)}) output_objects.append({'object_type': 'link', 'text' : 'Download zip archive', 'destination' : os.path.join('..', client_dir, script_zip)})
</style> ''' % (visibility_mods % {'main_class': main_class}) # Please note that base_dir must end in slash to avoid access to other # user dirs when own name is a prefix of another user name base_dir = os.path.abspath(os.path.join(base_dir, target_dir)) + os.sep if not os.path.isdir(base_dir): logger.error('%s called on missing base_dir: %s' % (op_name, base_dir)) output_objects.append({'object_type': 'error_text', 'text': 'No such %s!' % page_title.lower() }) return (output_objects, returnvalues.CLIENT_ERROR) title_entry = find_entry(output_objects, 'title') title_entry['text'] = page_title title_entry['skipwidgets'] = not widgets title_entry['skipuserstyle'] = not userstyle user_settings = title_entry.get('user_settings', {}) open_button_id = 'open_fancy_upload' form_method = 'post' csrf_limit = get_csrf_limit(configuration) fill_helpers = {'dest_dir': current_dir + os.sep, 'share_id': share_id, 'flags': flags, 'tmp_flags': flags, 'long_set': long_list(flags), 'recursive_set': recursive(flags), 'all_set': all(flags), 'fancy_open': open_button_id, 'fancy_dialog': fancy_upload_html(configuration), 'form_method': form_method, 'csrf_field': csrf_field, 'csrf_limit': csrf_limit}
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False, op_menu=False) defaults = signature()[1] (validate_status, accepted) = validate_input(user_arguments_dict, defaults, output_objects, allow_rejects=False) if not validate_status: logger.warning('%s invalid input: %s' % (op_name, accepted)) return (accepted, returnvalues.CLIENT_ERROR) if not correct_handler('POST'): output_objects.append( {'object_type': 'error_text', 'text' : 'Only accepting POST requests to prevent unintended updates'}) return (output_objects, returnvalues.CLIENT_ERROR) title_entry = find_entry(output_objects, 'title') title_entry['text'] = '%s certificate request' % configuration.short_title title_entry['skipmenu'] = True output_objects.append({'object_type': 'header', 'text' : '%s certificate request' % \ configuration.short_title }) admin_email = configuration.admin_email smtp_server = configuration.smtp_server user_pending = os.path.abspath(configuration.user_pending) # force name to capitalized form (henrik karlsen -> Henrik Karlsen) # please note that we get utf8 coded bytes here and title() treats such # chars as word termination. Temporarily force to unicode. raw_name = accepted['cert_name'][-1].strip() try: cert_name = force_utf8(force_unicode(raw_name).title()) except Exception: cert_name = raw_name.title() country = accepted['country'][-1].strip().upper() state = accepted['state'][-1].strip().title() org = accepted['org'][-1].strip() # lower case email address email = accepted['email'][-1].strip().lower() password = accepted['password'][-1] verifypassword = accepted['verifypassword'][-1] # keep comment to a single line comment = accepted['comment'][-1].replace('\n', ' ') # single quotes break command line format - remove comment = comment.replace("'", ' ') if password != verifypassword: output_objects.append({'object_type': 'error_text', 'text' : 'Password and verify password are not identical!' }) return (output_objects, returnvalues.CLIENT_ERROR) # TODO: move this check to conf? if not forced_org_email_match(org, email, configuration): output_objects.append({'object_type': 'error_text', 'text' : '''Illegal email and organization combination: Please read and follow the instructions in red on the request page! If you are a student with only a @*.ku.dk address please just use KU as organization. As long as you state that you want the certificate for course purposes in the comment field, you will be given access to the necessary resources anyway. '''}) return (output_objects, returnvalues.CLIENT_ERROR) user_dict = { 'full_name': cert_name, 'organization': org, 'state': state, 'country': country, 'email': email, 'comment': comment, 'password': base64.b64encode(password), 'expire': int(time.time() + cert_valid_days * 24 * 60 * 60), 'openid_names': [], } fill_distinguished_name(user_dict) user_id = user_dict['distinguished_name'] user_dict['authorized'] = (user_id == client_id) if configuration.user_openid_providers and configuration.user_openid_alias: user_dict['openid_names'] += \ [user_dict[configuration.user_openid_alias]] logger.info('got reqcert request: %s' % user_dict) # For testing only if cert_name.upper().find('DO NOT SEND') != -1: output_objects.append({'object_type': 'text', 'text' : "Test request ignored!"}) return (output_objects, returnvalues.OK) req_path = None try: (os_fd, req_path) = tempfile.mkstemp(dir=user_pending) os.write(os_fd, dumps(user_dict)) os.close(os_fd) except Exception, err: logger.error('Failed to write certificate request to %s: %s' % (req_path, err)) output_objects.append({'object_type': 'error_text', 'text' : 'Request could not be sent to grid administrators. Please contact them manually on %s if this error persists.' % admin_email}) return (output_objects, returnvalues.SYSTEM_ERROR)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] title_entry = find_entry(output_objects, 'title') label = "%s" % configuration.site_vgrid_label title_entry['text'] = '%s Resource Monitor' % label (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) meta = '''<meta http-equiv="refresh" content="%s" /> ''' % configuration.sleep_secs add_import = ''' <script type="text/javascript" src="/images/js/jquery.tablesorter.js"></script> ''' add_init = '' add_ready = ''' // table initially sorted by col. 1 (name) var sortOrder = [[1,0]]; // use image path for sorting if there is any inside var imgTitle = function(contents) { var key = $(contents).find("a").attr("class"); if (key == null) { key = $(contents).html(); } return key; } $("table.monitor").tablesorter({widgets: ["zebra"], textExtraction: imgTitle, }); $("table.monitor").each(function () { try { $(this).trigger("sorton", [sortOrder]); } catch(err) { /* tablesorter chokes on empty tables - just continue */ } }); ''' title_entry['script']['advanced'] += add_import title_entry['script']['init'] += add_init title_entry['script']['ready'] += add_ready title_entry['meta'] = meta vgrid_access = user_vgrid_access(configuration, client_id) vgrid_list = accepted['vgrid_name'] if all_vgrids in accepted['vgrid_name']: vgrid_list = [i for i in vgrid_list if all_vgrids != i]\ + vgrid_access # Force list to sequence of unique entries for vgrid_name in set(vgrid_list): html = '' if not vgrid_is_owner_or_member(vgrid_name, client_id, configuration): output_objects.append({'object_type': 'error_text', 'text': '''You must be an owner or member of %s %s to access the monitor.''' % (vgrid_name, label)}) return (output_objects, returnvalues.CLIENT_ERROR) monitor_file = os.path.join(configuration.vgrid_home, vgrid_name, '%s.html' % configuration.vgrid_monitor) try: monitor_fd = open(monitor_file, 'r') past_header = False for line in monitor_fd: if -1 != line.find('end of raw header'): past_header = True continue if not past_header: continue if -1 != line.find('begin raw footer:'): break html += str(line) monitor_fd.close() except Exception, exc: output_objects.append({'object_type': 'error_text', 'text': 'Error reading %s monitor page (%s)' % (label, exc)}) return (output_objects, returnvalues.SYSTEM_ERROR) output_objects.append({'object_type': 'html_form', 'text': html})
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Show Runtime Environment Details' (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) re_name = accepted['re_name'][-1] output_objects.append({ 'object_type': 'header', 'text': 'Show runtime environment details' }) if not valid_dir_input(configuration.re_home, re_name): logger.warning( "possible illegal directory traversal attempt re_name '%s'" % re_name) output_objects.append({ 'object_type': 'error_text', 'text': 'Illegal runtime environment name: "%s"' % re_name }) return (output_objects, returnvalues.CLIENT_ERROR) if not is_runtime_environment(re_name, configuration): output_objects.append({ 'object_type': 'error_text', 'text': "'%s' is not an existing runtime environment!" % re_name }) return (output_objects, returnvalues.CLIENT_ERROR) title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Runtime environment details' (re_dict, msg) = get_re_dict(re_name, configuration) if not re_dict: output_objects.append({ 'object_type': 'error_text', 'text': 'Could not read details for "%s"' % msg }) return (output_objects, returnvalues.SYSTEM_ERROR) # Set providers explicitly after build_reitem_object to avoid import loop re_item = build_reitem_object(configuration, re_dict) re_name = re_item['name'] re_item['providers'] = resources_using_re(configuration, re_name) re_item['resource_count'] = len(re_item['providers']) output_objects.append(re_item) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) status = returnvalues.OK defaults = signature()[1] title_entry = find_entry(output_objects, 'title') label = "%s" % configuration.site_vgrid_label title_entry['text'] = "%s Management" % label (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) operation = accepted['operation'][-1] caching = (accepted['caching'][-1].lower() in ('true', 'yes')) if not operation in allowed_operations: output_objects.append({ 'object_type': 'error_text', 'text': '''Operation must be one of %s.''' % ', '.join(allowed_operations) }) return (output_objects, returnvalues.OK) logger.info("%s %s begin for %s" % (op_name, operation, client_id)) vgrid_items, active_vgrid_links = [], [] member_list = { 'object_type': 'vgrid_list', 'vgrids': vgrid_items, 'components': active_vgrid_links } # Check if user wants advanced VGrid component links user_settings = title_entry.get('user_settings', {}) collaboration_links = user_settings.get('SITE_COLLABORATION_LINKS', 'default') if not collaboration_links in configuration.site_collaboration_links or \ collaboration_links == 'default': active_vgrid_links += configuration.site_default_vgrid_links elif collaboration_links == 'advanced': active_vgrid_links += configuration.site_advanced_vgrid_links # General fill helpers including CSRF fields form_method = 'post' csrf_limit = get_csrf_limit(configuration) fill_helpers = { 'vgrid_label': label, 'form_method': form_method, 'csrf_field': csrf_field, 'csrf_limit': csrf_limit } if operation in show_operations: # jquery support for tablesorter and confirmation on request and leave # table initially sorted by col. 2 (admin), then 3 (member), then 0 (name) # NOTE: We distinguish between caching on page load and forced refresh refresh_helper = 'ajax_vgridman("%s", %s, %%s)' refresh_call = refresh_helper % (label, active_vgrid_links) table_spec = { 'table_id': 'vgridtable', 'sort_order': '[[2,1],[3,1],[0,0]]', 'refresh_call': refresh_call % 'false' } (add_import, add_init, add_ready) = man_base_js(configuration, [table_spec]) if operation == "show": add_ready += '%s;' % (refresh_call % 'true') title_entry['script']['advanced'] += add_import title_entry['script']['init'] += add_init title_entry['script']['ready'] += add_ready output_objects.append({ 'object_type': 'html_form', 'text': man_base_html(configuration) }) # Append VGrid alias note if custom if label != 'VGrid': long_label = '%ss (i.e. VGrids)' % label else: long_label = "%ss" % label output_objects.append({ 'object_type': 'header', 'text': "%s" % long_label }) output_objects.append({ 'object_type': 'text', 'text': '''%ss share files, a number of collaboration tools and resources. Members can access web pages, files, tools and resources. Owners can additionally edit pages, as well as add and remove members or resources.''' % label }) if label != 'VGrid': output_objects.append({ 'object_type': 'text', 'text': """Please note that for historical reasons %ss are also referred to as VGrids in some contexts.""" % label }) output_objects.append({ 'object_type': 'sectionheader', 'text': '%ss managed on this server' % label }) # Helper forms for requests and removes for post_type in ["vgridowner", "vgridmember"]: target_op = 'sendrequestaction' csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) helper = html_post_helper( 'req%s' % post_type, '%s.py' % target_op, { 'vgrid_name': '__DYNAMIC__', 'request_type': post_type, 'request_text': '', csrf_field: csrf_token }) output_objects.append({'object_type': 'html_form', 'text': helper}) for post_type in ["vgridowner", "vgridmember"]: target_op = 'rm%s' % post_type csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) helper = html_post_helper( target_op, '%s.py' % target_op, { 'vgrid_name': '__DYNAMIC__', 'cert_id': client_id, csrf_field: csrf_token }) output_objects.append({'object_type': 'html_form', 'text': helper}) output_objects.append({ 'object_type': 'table_pager', 'entry_name': '%ss' % label, 'default_entries': default_pager_entries }) if operation in list_operations: logger.info("get vgrid map with caching %s" % caching) vgrid_map = get_vgrid_map(configuration, caching=caching) member_list['pending_updates'] = False if caching: modified_vgrids, _ = check_vgrids_modified(configuration) if modified_vgrids: logger.info("pending cache updates: %s" % modified_vgrids) member_list['pending_updates'] = True else: logger.info("no pending cache updates") vgrid_list = vgrid_map[VGRIDS].keys() # Iterate through vgrids and print details for each if 'monitor' in active_vgrid_links: vgrid_list = [all_vgrids] + vgrid_list else: vgrid_list.remove(default_vgrid) # User vgrid_list here to include default and all mangling above for vgrid_name in vgrid_list: vgrid_dict = vgrid_map[VGRIDS].get(vgrid_name, {}) settings_dict = dict(vgrid_dict.get(SETTINGS, [])) # Mark and show hidden vgrids if owner or member and hide otherwise view_icon, hidden_status = "infolink", " " if settings_dict.get('hidden', False): if client_id in vgrid_dict[OWNERS] + vgrid_dict[MEMBERS]: logger.debug("show hidden vgrid %s for participant" % vgrid_name) view_icon, hidden_status = "shadeinfolink", " hidden " else: logger.debug("skip hidden vgrid %s" % vgrid_name) continue vgrid_obj = {'object_type': 'vgrid', 'name': vgrid_name} if vgrid_name == default_vgrid: # Everybody is member and allowed to see statistics, Noone # can own it or leave it. Do not add any page links. vgrid_obj['privatemonitorlink'] = { 'object_type': 'link', 'destination': 'showvgridmonitor.py?vgrid_name=%s' % vgrid_name, 'class': 'monitorlink iconspace', 'title': 'View %s monitor' % vgrid_name, 'text': 'View' } vgrid_obj['memberlink'] = { 'object_type': 'link', 'destination': '', 'class': 'infolink iconspace', 'title': 'Every user is member of the %s %s' % (default_vgrid, label), 'text': '' } vgrid_obj['administratelink'] = { 'object_type': 'link', 'destination': '', 'class': 'infolink iconspace', 'title': 'Nobody owns the %s %s' % (default_vgrid, label), 'text': '' } vgrid_obj['viewvgridlink'] = { 'object_type': 'link', 'destination': 'viewvgrid.py?vgrid_name=%s' % vgrid_name, 'class': 'infolink iconspace', 'title': 'View details for the %s %s' % (default_vgrid, label), 'text': '' } vgrid_items.append(vgrid_obj) continue elif vgrid_name == all_vgrids: # Only show global monitor link for all_vgrids, Noone # can own it or leave it. Do not add any page links. vgrid_obj['privatemonitorlink'] = { 'object_type': 'link', 'destination': 'showvgridmonitor.py?vgrid_name=%s' % vgrid_name, 'class': 'monitorlink iconspace', 'title': 'View global monitor', 'text': 'View' } vgrid_obj['memberlink'] = { 'object_type': 'link', 'destination': '', 'class': 'infolink iconspace', 'title': 'Not a real %s - only for global monitor' % label, 'text': '' } vgrid_obj['administratelink'] = { 'object_type': 'link', 'destination': '', 'class': '', 'title': '', 'text': '' } vgrid_obj['viewvgridlink'] = { 'object_type': 'link', 'destination': '', 'class': 'infolink iconspace', 'title': 'Not a real %s - only for global monitor' % label, 'text': '' } vgrid_items.append(vgrid_obj) continue # links for everyone: public pages and membership request vgrid_obj['publicscmlink'] = { 'object_type': 'link', 'destination': '%s/vgridpublicscm/%s' % (configuration.migserver_http_url, vgrid_name), 'class': 'scmlink public iconspace', 'title': 'Open %s public SCM' % vgrid_name, 'text': 'Open' } vgrid_obj['publictrackerlink'] = { 'object_type': 'link', 'destination': '%s/vgridpublictracker/%s' % (configuration.migserver_http_url, vgrid_name), 'class': 'trackerlink public iconspace', 'title': 'Open %s public tracker' % vgrid_name, 'text': 'Open' } vgrid_obj['enterpubliclink'] = { 'object_type': 'link', 'destination': '%s/vgrid/%s/path/index.html' % (configuration.migserver_http_url, vgrid_name), 'class': 'urllink member iconspace', 'title': 'View public %s web page' % vgrid_name, 'text': 'View' } # Link to show vgrid details vgrid_obj['viewvgridlink'] = \ {'object_type': 'link', 'destination': 'viewvgrid.py?vgrid_name=%s' % vgrid_name, 'class': '%s iconspace' % view_icon, 'title': 'View details for the %s%s%s' % (vgrid_name, hidden_status, label), 'text': ''} # link to become member: overwritten later for members vgrid_obj['memberlink'] = { 'object_type': 'link', 'destination': "javascript: confirmDialog(%s, '%s', '%s', %s);" % ('reqvgridmember', "Request membership of " + vgrid_name + ":<br/>\nPlease write a message to the owners (field below).", 'request_text', "{vgrid_name: '%s'}" % vgrid_name), 'class': 'addlink iconspace', 'title': 'Request membership of %s' % vgrid_name, 'text': '' } # link to become owner: overwritten later for owners vgrid_obj['administratelink'] = { 'object_type': 'link', 'destination': "javascript: confirmDialog(%s, '%s', '%s', %s);" % ('reqvgridowner', "Request ownership of " + vgrid_name + ":<br/>\nPlease write a message to the owners (field below).", 'request_text', "{vgrid_name: '%s'}" % vgrid_name), 'class': 'addadminlink iconspace', 'title': 'Request ownership of %s' % vgrid_name, 'text': '' } # members/owners are allowed to view private pages and monitor if client_id in vgrid_dict[OWNERS] + vgrid_dict[MEMBERS]: vgrid_obj['enterprivatelink'] = { 'object_type': 'link', 'destination': '../vgrid/%s/path/index.html' % vgrid_name, 'class': 'urllink owner iconspace', 'title': 'View private %s web page' % vgrid_name, 'text': 'View' } vgrid_obj['sharedfolderlink'] = { 'object_type': 'link', 'destination': 'fileman.py?path=%s/' % vgrid_name, 'class': 'sharedfolderlink iconspace', 'title': 'Open shared %s folder' % vgrid_name, 'text': 'Open' } vgrid_obj['memberscmlink'] = { 'object_type': 'link', 'destination': '/vgridscm/%s' % vgrid_name, 'class': 'scmlink member iconspace', 'title': 'View %s members scm' % vgrid_name, 'text': 'View' } vgrid_obj['membertrackerlink'] = { 'object_type': 'link', 'destination': '/vgridtracker/%s' % vgrid_name, 'class': 'trackerlink member iconspace', 'title': 'View %s members tracker' % vgrid_name, 'text': 'View' } vgrid_obj['privateforumlink'] = { 'object_type': 'link', 'destination': 'vgridforum.py?vgrid_name=%s' % vgrid_name, 'class': 'forumlink iconspace', 'title': 'Open %s private forum' % vgrid_name, 'text': 'Open' } vgrid_obj['privateworkflowslink'] = { 'object_type': 'link', 'destination': 'vgridworkflows.py?vgrid_name=%s' % vgrid_name, 'class': 'workflowslink iconspace', 'title': 'Open %s private workflows' % vgrid_name, 'text': 'Open' } vgrid_obj['privatemonitorlink'] = { 'object_type': 'link', 'destination': 'showvgridmonitor.py?vgrid_name=%s' % vgrid_name, 'class': 'monitorlink iconspace', 'title': 'View %s monitor' % vgrid_name, 'text': 'View' } # to leave this VGrid (remove ourselves). Note that we are # going to overwrite the link later for owners. vgrid_obj['memberlink'].update({ 'destination': "javascript: confirmDialog(%s, '%s', %s, %s);" % ('rmvgridmember', "Really leave " + vgrid_name + "?", 'undefined', "{vgrid_name: '%s'}" % vgrid_name), 'class': 'removelink iconspace', 'title': 'Leave %s members' % vgrid_name, }) # owners are allowed to edit pages and administrate if client_id in vgrid_dict[OWNERS]: vgrid_obj['ownerscmlink'] = { 'object_type': 'link', 'destination': '/vgridownerscm/%s' % vgrid_name, 'class': 'scmlink owner iconspace', 'title': 'View %s owners scm' % vgrid_name, 'text': 'View' } vgrid_obj['ownertrackerlink'] = { 'object_type': 'link', 'destination': '/vgridownertracker/%s' % vgrid_name, 'class': 'trackerlink owner iconspace', 'title': 'View %s owners tracker' % vgrid_name, 'text': 'View' } # correct the link to leave the VGrid vgrid_obj['memberlink'].update({ 'destination': "javascript: confirmDialog(%s, '%s', %s, %s);" % ('rmvgridowner', "Really leave " + vgrid_name + "?", 'undefined', "{vgrid_name: '%s'}" % vgrid_name), 'class': 'removeadminlink iconspace', 'title': 'Leave %s owners' % vgrid_name }) # add more links: administrate and edit pages vgrid_obj['administratelink'] = { 'object_type': 'link', 'destination': 'adminvgrid.py?vgrid_name=%s' % vgrid_name, 'class': 'adminlink iconspace', 'title': 'Administrate %s' % vgrid_name, 'text': '' } vgrid_obj['editprivatelink'] = { 'object_type': 'link', 'destination': 'fileman.py?path=private_base/%s/' % vgrid_name, 'class': 'editlink owner iconspace', 'title': 'Edit private %s web page' % vgrid_name, 'text': 'Edit' } vgrid_obj['editpubliclink'] = { 'object_type': 'link', 'destination': 'fileman.py?path=public_base/%s/' % vgrid_name, 'class': 'editlink member iconspace', 'title': 'Edit public %s web page' % vgrid_name, 'text': 'Edit' } vgrid_items.append(vgrid_obj) if operation == "show": # insert dummy placeholder to build table vgrid_obj = {'object_type': 'vgrid', 'name': default_vgrid} for field in active_vgrid_links: vgrid_obj[field] = '' vgrid_items.append(vgrid_obj) output_objects.append(member_list) if operation in show_operations: user_map = get_full_user_map(configuration) user_dict = user_map.get(client_id, None) # Optional limitation of create vgrid permission if user_dict and vgrid_create_allowed(configuration, user_dict): output_objects.append({ 'object_type': 'sectionheader', 'text': 'Additional %ss' % label }) output_objects.append({ 'object_type': 'text', 'text': '''Please enter a name for the new %(vgrid_label)s to add, using slashes to specify nesting. I.e. if you own a %(vgrid_label)s called ABC, you can create a sub-%(vgrid_label)s called DEF by entering ABC/DEF below. ''' % fill_helpers }) target_op = 'createvgrid' csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) fill_helpers.update({ 'target_op': target_op, 'csrf_token': csrf_token }) output_objects.append({ 'object_type': 'html_form', 'text': ''' <form method="%(form_method)s" action="%(target_op)s.py"> <input type="hidden" name="%(csrf_field)s" value="%(csrf_token)s" /> <input class="p60width" type="text" name="vgrid_name" required pattern="[a-zA-Z0-9 /_.-]*" title="unique name of ASCII letters and digits separated only by underscores, periods, spaces and hyphens. Slashes are additionally allowed when creating nested sub-%(vgrid_label)ss" /> <input type="hidden" name="output_format" value="html" /> <input type="submit" value="Create %(vgrid_label)s" /> </form> ''' % fill_helpers }) output_objects.append({ 'object_type': 'sectionheader', 'text': 'Request Access to %ss' % label }) output_objects.append({ 'object_type': 'text', 'text': '''You can request access to %(vgrid_label)ss using the individual plus-icons above directly or by entering the name of the %(vgrid_label)s to request access to, what kind of access and an optional message to the admins below''' % fill_helpers }) target_op = 'sendrequestaction' csrf_token = make_csrf_token(configuration, form_method, target_op, client_id, csrf_limit) fill_helpers.update({'target_op': target_op, 'csrf_token': csrf_token}) output_objects.append({ 'object_type': 'html_form', 'text': ''' <form method="%(form_method)s" action="%(target_op)s.py"> <input type="hidden" name="%(csrf_field)s" value="%(csrf_token)s" /> <input class="p60width" type="text" name="vgrid_name" required pattern="[a-zA-Z0-9 /_.-]*" title="the name of an existing %(vgrid_label)s" /> <select class="styled-select html-select" name="request_type"> <option value="vgridmember">membership</option> <option value="vgridowner">ownership</option> </select> <br/> <input class="p60width" type="text" name="request_text" required /> <input type="hidden" name="output_format" value="html" /> <input type="submit" value="Request %(vgrid_label)s access" /> </form> ''' % fill_helpers }) logger.info("%s %s end for %s" % (op_name, operation, client_id)) return (output_objects, status)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) client_dir = client_id_dir(client_id) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) if not correct_handler('POST'): output_objects.append( {'object_type': 'error_text', 'text' : 'Only accepting POST requests to prevent unintended updates'}) return (output_objects, returnvalues.CLIENT_ERROR) vgrid_name = accepted['vgrid_name'][-1].strip() title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Create %s' % configuration.site_vgrid_label output_objects.append({'object_type': 'header', 'text': 'Create %s' % \ configuration.site_vgrid_label}) # No owner check here so we need to specifically check for illegal # directory access reserved_names = (default_vgrid, any_vgrid, all_vgrids) if vgrid_name in reserved_names or \ not valid_dir_input(configuration.vgrid_home, vgrid_name): output_objects.append({'object_type': 'error_text', 'text' : 'Illegal vgrid_name: %s' % vgrid_name}) logger.warning("""createvgrid possible illegal directory access attempt by '%s': vgrid_name '%s'""" % (client_id, vgrid_name)) return (output_objects, returnvalues.CLIENT_ERROR) user_map = get_full_user_map(configuration) user_dict = user_map.get(client_id, None) # Optional limitation of create vgrid permission if not user_dict or \ not vgrid_create_allowed(configuration, user_dict): logger.warning("user %s is not allowed to create %ss!" % \ (client_id, configuration.site_vgrid_label)) output_objects.append( {'object_type': 'error_text', 'text' : 'Only privileged users can create %ss' % \ configuration.site_vgrid_label}) return (output_objects, returnvalues.CLIENT_ERROR) # Please note that base_dir must end in slash to avoid access to other # user dirs when own name is a prefix of another user name base_dir = os.path.abspath(os.path.join(configuration.vgrid_home, vgrid_name)) + os.sep public_base_dir = \ os.path.abspath(os.path.join(configuration.vgrid_public_base, vgrid_name)) + os.sep public_scm_dir = \ os.path.abspath(os.path.join(configuration.vgrid_public_base, vgrid_name, '.vgridscm')) + os.sep public_tracker_dir = \ os.path.abspath(os.path.join(configuration.vgrid_public_base, vgrid_name, '.vgridtracker')) + os.sep private_base_dir = \ os.path.abspath(os.path.join(configuration.vgrid_private_base, vgrid_name)) + os.sep private_scm_dir = \ os.path.abspath(os.path.join(configuration.vgrid_private_base, vgrid_name, '.vgridscm')) + os.sep private_tracker_dir = \ os.path.abspath(os.path.join(configuration.vgrid_private_base, vgrid_name, '.vgridtracker')) + os.sep private_forum_dir = \ os.path.abspath(os.path.join(configuration.vgrid_private_base, vgrid_name, '.vgridforum')) + os.sep vgrid_files_dir = \ os.path.abspath(os.path.join(configuration.vgrid_files_home, vgrid_name)) + os.sep vgrid_scm_dir = \ os.path.abspath(os.path.join(configuration.vgrid_files_home, vgrid_name, '.vgridscm')) + os.sep vgrid_tracker_dir = \ os.path.abspath(os.path.join(configuration.vgrid_files_home, vgrid_name, '.vgridtracker')) + os.sep # does vgrid exist? if os.path.isdir(base_dir): output_objects.append( {'object_type': 'error_text', 'text' : '%s %s cannot be created because it already exists!' % (configuration.site_vgrid_label, vgrid_name)}) return (output_objects, returnvalues.CLIENT_ERROR) # verify that client is owner of imada or imada/topology if trying to # create imada/topology/test vgrid_name_list = vgrid_name.split('/') vgrid_name_list_length = len(vgrid_name_list) if vgrid_name_list_length <= 0: output_objects.append({'object_type': 'error_text', 'text' : 'vgrid_name not specified?'}) return (output_objects, returnvalues.SYSTEM_ERROR) elif vgrid_name_list_length == 1: # anyone can create base vgrid new_base_vgrid = True else: new_base_vgrid = False vgrid_name_without_last_fragment = \ '/'.join(vgrid_name_list[0:vgrid_name_list_length - 1]) parent_base = os.path.dirname(base_dir.rstrip(os.sep)) if not os.path.isdir(parent_base): output_objects.append( {'object_type': 'error_text', 'text' : 'Parent %s %s does not exist!' % \ (configuration.site_vgrid_label, vgrid_name_without_last_fragment) }) return (output_objects, returnvalues.CLIENT_ERROR) if not vgrid_is_owner(vgrid_name_without_last_fragment, client_id, configuration): output_objects.append( {'object_type': 'error_text', 'text' : 'You must own a parent %s to create a sub vgrid' % \ configuration.site_vgrid_label }) return (output_objects, returnvalues.CLIENT_ERROR) # make sure all dirs can be created (that a file or directory with the same # name do not exist prior to the vgrid creation) try_again_string = \ """%s cannot be created, a file or directory exists with the same name, please try again with a new name!""" % configuration.site_vgrid_label if os.path.exists(public_base_dir): output_objects.append({'object_type': 'error_text', 'text' : try_again_string}) return (output_objects, returnvalues.CLIENT_ERROR) if os.path.exists(private_base_dir): output_objects.append({'object_type': 'error_text', 'text' : try_again_string}) return (output_objects, returnvalues.CLIENT_ERROR) if os.path.exists(vgrid_files_dir): output_objects.append({'object_type': 'error_text', 'text' : try_again_string}) return (output_objects, returnvalues.CLIENT_ERROR) # create directory to store vgrid files try: os.mkdir(base_dir) except Exception, exc: output_objects.append( {'object_type': 'error_text', 'text' : """Could not create %(_label)s directory, remember to create parent %(_label)s before creating a sub-%(_label)s.""" % \ {'_label': configuration.site_vgrid_label} }) return (output_objects, returnvalues.CLIENT_ERROR)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) title_entry = find_entry(output_objects, 'title') title_entry['text'] = 'Delete frozen archive' defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) flavor = accepted['flavor'][-1] if not safe_handler(configuration, 'post', op_name, client_id, get_csrf_limit(configuration), accepted): output_objects.append({ 'object_type': 'error_text', 'text': '''Only accepting CSRF-filtered POST requests to prevent unintended updates''' }) return (output_objects, returnvalues.CLIENT_ERROR) if not flavor in freeze_flavors.keys(): output_objects.append({ 'object_type': 'error_text', 'text': 'Invalid freeze flavor: %s' % flavor }) return (output_objects, returnvalues.CLIENT_ERROR) title = freeze_flavors[flavor]['deletefreeze_title'] output_objects.append({'object_type': 'header', 'text': title}) title_entry = find_entry(output_objects, 'title') title_entry['text'] = title if not configuration.site_enable_freeze: output_objects.append({ 'object_type': 'text', 'text': '''Freezing archives is disabled on this site. Please contact the site admins %s if you think it should be enabled. ''' % configuration.admin_email }) return (output_objects, returnvalues.OK) freeze_id = accepted['freeze_id'][-1] target = accepted['target'][-1] path_list = accepted['path'] if not target in valid_targets: output_objects.append({ 'object_type': 'error_text', 'text': 'Invalid delete freeze target: %s' % target }) return (output_objects, returnvalues.CLIENT_ERROR) # NB: the restrictions on freeze_id prevents illegal directory traversal if not is_frozen_archive(client_id, freeze_id, configuration): logger.error("%s: invalid freeze '%s': %s" % (op_name, client_id, freeze_id)) output_objects.append({ 'object_type': 'error_text', 'text': "No such frozen archive: '%s'" % freeze_id }) return (output_objects, returnvalues.CLIENT_ERROR) (load_status, freeze_dict) = get_frozen_archive(client_id, freeze_id, configuration, checksum_list=[]) if not load_status: logger.error("%s: load failed for '%s': %s" % (op_name, freeze_id, freeze_dict)) output_objects.append({ 'object_type': 'error_text', 'text': 'Could not read frozen archive details for %s' % freeze_id }) return (output_objects, returnvalues.SYSTEM_ERROR) # Make sure the frozen archive belongs to the user trying to delete it if client_id != freeze_dict['CREATOR']: logger.error("%s: illegal access attempt for '%s': %s" % (op_name, freeze_id, client_id)) output_objects.append({ 'object_type': 'error_text', 'text': 'You are not the owner of frozen archive "%s"' % freeze_id }) return (output_objects, returnvalues.CLIENT_ERROR) if freeze_dict.get('FLAVOR', 'freeze') != flavor: logger.error("%s: flavor mismatch for '%s': %s vs %s" % (op_name, freeze_id, flavor, freeze_dict)) output_objects.append({ 'object_type': 'error_text', 'text': 'No such %s archive "%s"' % (flavor, freeze_id) }) return (output_objects, returnvalues.CLIENT_ERROR) # Prevent user-delete of the frozen archive if configuration forbids it. # We exclude any archives in the pending intermediate freeze state. # Freeze admins are also excluded from the restrictions. state = freeze_dict.get('STATE', keyword_final) if state == keyword_updating: output_objects.append({ 'object_type': 'error_text', 'text': "Can't change %s archive %s which is currently being updated" % (flavor, freeze_id) }) output_objects.append({ 'object_type': 'link', 'destination': 'showfreeze.py?freeze_id=%s;flavor=%s' % (freeze_id, flavor), 'class': 'viewarchivelink iconspace genericbutton', 'title': 'View details about your %s archive' % flavor, 'text': 'View details', }) return (output_objects, returnvalues.CLIENT_ERROR) elif state == keyword_final and \ flavor in configuration.site_permanent_freeze and \ not client_id in configuration.site_freeze_admins: output_objects.append({ 'object_type': 'error_text', 'text': "Can't change %s archives like '%s' yourself due to site policy" % (flavor, freeze_id) }) return (output_objects, returnvalues.CLIENT_ERROR) client_dir = client_id_dir(client_id) user_archives = os.path.join(configuration.freeze_home, client_dir) # Please note that base_dir must end in slash to avoid access to other # user archive dirs if own name is a prefix of another archive name base_dir = os.path.abspath(os.path.join(user_archives, freeze_id)) + os.sep if target == TARGET_ARCHIVE: # Delete the entire freeze archive (del_status, msg) = delete_frozen_archive(freeze_dict, client_id, configuration) # If something goes wrong when trying to delete freeze archive # freeze_id, an error is displayed. if not del_status: logger.error("%s: failed for '%s': %s" % (op_name, freeze_id, msg)) output_objects.append({ 'object_type': 'error_text', 'text': 'Could not remove entire %s archive %s: %s' % (flavor, freeze_id, msg) }) return (output_objects, returnvalues.SYSTEM_ERROR) # If deletion of frozen archive freeze_id is successful, we just # return OK else: logger.info("%s: successful for '%s': %s" % (op_name, freeze_id, client_id)) output_objects.append({ 'object_type': 'text', 'text': 'Successfully deleted %s archive: "%s"' % (flavor, freeze_id) }) elif target == TARGET_PATH: # Delete individual files in non-final archive del_paths = [] for path in path_list: # IMPORTANT: path must be expanded to abs for proper chrooting server_path = os.path.join(base_dir, path) abs_path = os.path.abspath(server_path) if not valid_user_path(configuration, abs_path, base_dir, False): # Out of bounds! logger.warning( '%s tried to %s del restricted path %s ! ( %s)' % (client_id, op_name, abs_path, path)) output_objects.append({ 'object_type': 'error_text', 'text': 'Not allowed to delete %s - outside archive %s !' % (path, freeze_id) }) continue del_paths.append(path) (del_status, msg_list) = delete_archive_files(freeze_dict, client_id, del_paths, configuration) # If something goes wrong when trying to delete files from archive # freeze_id, an error is displayed. if not del_status: logger.error("%s: delete archive file(s) failed for '%s':\n%s" % (op_name, freeze_id, '\n'.join(msg_list))) output_objects.append({ 'object_type': 'error_text', 'text': 'Could not remove file(s) from archive %s: %s' % (freeze_id, '\n '.join(msg_list)) }) return (output_objects, returnvalues.SYSTEM_ERROR) # If deletion of files from archive freeze_id is successful, we just # return OK else: logger.info("%s: delete %d files successful for '%s': %s" % (op_name, len(path_list), freeze_id, client_id)) output_objects.append({ 'object_type': 'text', 'text': 'Successfully deleted %d file(s) from archive: "%s"' % (len(path_list), freeze_id) }) # Success - show link to overview output_objects.append({ 'object_type': 'link', 'destination': 'freezedb.py', 'class': 'infolink iconspace', 'title': 'Show archives', 'text': 'Show archives' }) return (output_objects, returnvalues.OK)