def refresh_vgrid_map(configuration): """Refresh map of users and resources with their direct vgrid participation. That is, without inheritance. Uses a pickled dictionary for efficiency. Resource and user IDs are stored in their raw (non-anonymized form). Only update map for users and resources that updated conf after last map save. """ dirty = {} vgrid_changes = {} map_path = os.path.join(configuration.mig_system_files, "vgrid.map") lock_path = os.path.join(configuration.mig_system_files, "vgrid.lock") lock_handle = open(lock_path, 'a') fcntl.flock(lock_handle.fileno(), fcntl.LOCK_EX) vgrid_map, map_stamp = load_vgrid_map(configuration, do_lock=False) vgrid_helper = {default_vgrid: {RESOURCES: '*', OWNERS: '', MEMBERS: '*'}} if not vgrid_map.has_key(VGRIDS): vgrid_map[VGRIDS] = vgrid_helper dirty[VGRIDS] = dirty.get(VGRIDS, []) + [default_vgrid] if not vgrid_map.has_key(RESOURCES): vgrid_map[RESOURCES] = {} dirty[RESOURCES] = dirty.get(RESOURCES, []) if not vgrid_map.has_key(USERS): vgrid_map[USERS] = {} dirty[USERS] = dirty.get(USERS, []) # Find all vgrids and their allowed users and resources (status, all_vgrids) = vgrid_list_vgrids(configuration) if not status: all_vgrids = [] conf_read = [(RESOURCES, configuration.vgrid_resources, vgrid_resources), (OWNERS, configuration.vgrid_owners, vgrid_owners), (MEMBERS, configuration.vgrid_members, vgrid_members)] for vgrid in all_vgrids: for (field, name, list_call) in conf_read: conf_path = os.path.join(configuration.vgrid_home, vgrid, name) if not os.path.isfile(conf_path): configuration.logger.warning('missing file: %s' % (conf_path)) # Make sure vgrid dict exists before filling it vgrid_map[VGRIDS][vgrid] = vgrid_map[VGRIDS].get(vgrid, {}) vgrid_map[VGRIDS][vgrid][field] = [] dirty[VGRIDS] = dirty.get(VGRIDS, []) + [vgrid] elif not vgrid_map[VGRIDS].has_key(vgrid) or \ os.path.getmtime(conf_path) >= map_stamp: (status, entries) = list_call(vgrid, configuration, recursive=False) if not status: entries = [] vgrid_changes[vgrid] = (vgrid_map[VGRIDS].get(vgrid, []), entries) vgrid_map[VGRIDS][vgrid] = vgrid_map[VGRIDS].get(vgrid, {}) vgrid_map[VGRIDS][vgrid][field] = entries dirty[VGRIDS] = dirty.get(VGRIDS, []) + [vgrid] # Remove any missing vgrids from map missing_vgrids = [vgrid for vgrid in vgrid_map[VGRIDS].keys() \ if not vgrid in all_vgrids] for vgrid in missing_vgrids: vgrid_changes[vgrid] = (vgrid_map[VGRIDS][vgrid], []) del vgrid_map[VGRIDS][vgrid] dirty[VGRIDS] = dirty.get(VGRIDS, []) + [vgrid] # Find all resources and their vgrid assignments # TODO: use get_resource_map output instead? all_resources = list_resources(configuration.resource_home, only_valid=True) real_map = real_to_anon_res_map(configuration.resource_home) for res in all_resources: # Sandboxes do not change their vgrid participation if vgrid_map[RESOURCES].has_key(res) and sandbox_resource(res): continue conf_path = os.path.join(configuration.resource_home, res, "config") if not os.path.isfile(conf_path): continue if os.path.getmtime(conf_path) >= map_stamp: vgrid_map[RESOURCES][res] = get_all_exe_vgrids(res) assigned = [] all_exes = [i for i in vgrid_map[RESOURCES][res].keys() \ if not i in RES_SPECIALS] for exe in all_exes: exe_vgrids = vgrid_map[RESOURCES][res][exe] assigned += [i for i in exe_vgrids if i and i not in assigned] vgrid_map[RESOURCES][res][ASSIGN] = assigned vgrid_map[RESOURCES][res][ALLOW] = vgrid_map[RESOURCES][res].get(ALLOW, []) public_id = res anon_val = get_resource_fields(configuration.resource_home, res, ['ANONYMOUS'], configuration.logger) if anon_val.get('ANONYMOUS', True): public_id = real_map[res] vgrid_map[RESOURCES][res][RESID] = public_id dirty[RESOURCES] = dirty.get(RESOURCES, []) + [res] # Remove any missing resources from map missing_res = [res for res in vgrid_map[RESOURCES].keys() \ if not res in all_resources] for res in missing_res: del vgrid_map[RESOURCES][res] dirty[RESOURCES] = dirty.get(RESOURCES, []) + [res] # Update list of mutually agreed vgrid participations for dirty resources # and resources assigned to dirty vgrids configuration.logger.info("update res vgrid participations: %s" % vgrid_changes) update_res = [i for i in dirty.get(RESOURCES, []) if i not in MAP_SECTIONS] # configuration.logger.info("update vgrid allow res") for (vgrid, (old, new)) in vgrid_changes.items(): # configuration.logger.info("update res vgrid %s" % vgrid) for res in [i for i in vgrid_map[RESOURCES].keys() \ if i not in update_res]: # Sandboxes do not change their vgrid participation if sandbox_resource(res): continue # configuration.logger.info("update res vgrid %s for res %s" % (vgrid, res)) if vgrid_allowed(res, old) != vgrid_allowed(res, new): update_res.append(res) # configuration.logger.info("update res assign vgrid") for res in [i for i in update_res if i not in missing_res]: allow = [] for vgrid in vgrid_map[RESOURCES][res][ASSIGN]: if vgrid_allowed(res, vgrid_map[VGRIDS][vgrid][RESOURCES]): allow.append(vgrid) vgrid_map[RESOURCES][res][ALLOW] = allow configuration.logger.info("done updating vgrid res participations") # Find all users and their vgrid assignments # TODO: use get_user_map output instead? all_users = list_users(configuration.user_home) real_map = real_to_anon_user_map(configuration.user_home) for user in all_users: settings_path = os.path.join(configuration.user_settings, client_id_dir(user), settings_filename) profile_path = os.path.join(configuration.user_settings, client_id_dir(user), profile_filename) settings_mtime, profile_mtime = 0, 0 if os.path.isfile(settings_path): settings_mtime = os.path.getmtime(settings_path) if os.path.isfile(profile_path): profile_mtime = os.path.getmtime(profile_path) if settings_mtime + profile_mtime > 0: conf_mtime = max(settings_mtime, profile_mtime) user_conf = get_user_conf(user, configuration) else: conf_mtime = -1 user_conf = {} if conf_mtime >= map_stamp: vgrid_map[USERS][user] = user_conf vgrid_map[USERS][user][ASSIGN] = vgrid_map[USERS][user].get(ASSIGN, []) vgrid_map[USERS][user][ALLOW] = vgrid_map[USERS][user].get(ALLOW, []) public_id = user if user_conf.get('ANONYMOUS', True): public_id = real_map[user] vgrid_map[USERS][user][USERID] = public_id dirty[USERS] = dirty.get(USERS, []) + [user] # Remove any missing users from map missing_user = [user for user in vgrid_map[USERS].keys() \ if not user in all_users] for user in missing_user: del vgrid_map[USERS][user] dirty[USERS] = dirty.get(USERS, []) + [user] # Update list of mutually agreed vgrid participations for dirty users # and users assigned to dirty vgrids update_user = [i for i in dirty.get(USERS, []) if i not in MAP_SECTIONS] for (vgrid, (old, new)) in vgrid_changes.items(): for user in [i for i in vgrid_map[USERS].keys() \ if i not in update_user]: if vgrid_allowed(user, old) != vgrid_allowed(user, new): update_user.append(user) for user in [i for i in update_user if i not in missing_user]: allow = [] for vgrid in vgrid_map[USERS][user][ASSIGN]: if vgrid_allowed(user, vgrid_map[VGRIDS][vgrid][OWNERS]) or \ vgrid_allowed(user, vgrid_map[VGRIDS][vgrid][MEMBERS]): allow.append(vgrid) # users implicitly assign all vgrids vgrid_map[USERS][user][ASSIGN] = allow vgrid_map[USERS][user][ALLOW] = allow if dirty: try: dump(vgrid_map, map_path) except Exception, exc: configuration.logger.error("Could not save vgrid map: %s" % exc)
def refresh_resource_map(configuration): """Refresh map of resources and their configuration. Uses a pickled dictionary for efficiency. Resource IDs are stored in their raw (non-anonymized form). Only update map for resources that updated conf after last map save. """ dirty = [] map_path = os.path.join(configuration.mig_system_files, "resource.map") lock_path = os.path.join(configuration.mig_system_files, "resource.lock") lock_handle = open(lock_path, 'a') fcntl.flock(lock_handle.fileno(), fcntl.LOCK_EX) resource_map, map_stamp = load_resource_map(configuration, do_lock=False) # Find all resources and their configurations all_resources = list_resources(configuration.resource_home, only_valid=True) real_map = real_to_anon_res_map(configuration.resource_home) for res in all_resources: # Sandboxes do not change their configuration if resource_map.has_key(res) and sandbox_resource(res): continue conf_path = os.path.join(configuration.resource_home, res, "config") if not os.path.isfile(conf_path): continue conf_mtime = os.path.getmtime(conf_path) owners_path = os.path.join(configuration.resource_home, res, "owners") if not os.path.isfile(owners_path): continue owners_mtime = os.path.getmtime(owners_path) # init first time resource_map[res] = resource_map.get(res, {}) if not resource_map[res].has_key(CONF) or conf_mtime >= map_stamp: (status, res_conf) = get_resource_configuration( configuration.resource_home, res, configuration.logger) if not status: continue resource_map[res][CONF] = res_conf public_id = res if res_conf.get('ANONYMOUS', True): public_id = real_map[res] resource_map[res][RESID] = public_id resource_map[res][MODTIME] = map_stamp dirty += [res] if not resource_map[res].has_key(OWNERS) or owners_mtime >= map_stamp: owners = load(owners_path) resource_map[res][OWNERS] = owners resource_map[res][MODTIME] = map_stamp dirty += [res] # Remove any missing resources from map missing_res = [res for res in resource_map.keys() \ if not res in all_resources] for res in missing_res: del resource_map[res] dirty += [res] if dirty: try: dump(resource_map, map_path) except Exception, exc: configuration.logger.error("Could not save resource map: %s" % exc)
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) 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)
logger = configuration.logger persistent_hosts = {} resource_path = configuration.resource_home for unique_resource_name in os.listdir(configuration.resource_home): res_dir = os.path.realpath(configuration.resource_home + os.sep + unique_resource_name) # skip all dot dirs - they are from repos etc and _not_ jobs if res_dir.find(os.sep + '.') != -1: continue if not os.path.isdir(res_dir): continue dir_name = os.path.basename(res_dir) if sandbox_resource(dir_name): continue try: (status, res_conf) = \ get_resource_configuration(configuration.resource_home, unique_resource_name, logger) if not status: continue if res_conf.has_key('SSHMULTIPLEX') and res_conf['SSHMULTIPLEX' ]: print 'adding multiplexing resource %s'\ % unique_resource_name fqdn = res_conf['HOSTURL'] res_conf['HOMEDIR'] = res_dir persistent_hosts[fqdn] = res_conf except Exception, err:
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)