Beispiel #1
0
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': 'Create runtime environment'
    })
    (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_template = accepted['re_template'][-1].upper().strip()
    software_entries = int(accepted['software_entries'][-1])
    environment_entries = int(accepted['environment_entries'][-1])
    testprocedure_entry = int(accepted['testprocedure_entry'][-1])

    template = {}
    if re_template:
        if not is_runtime_environment(re_template, configuration):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                "re_template ('%s') is not a valid existing runtime env!" %
                re_template
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

        (template, msg) = get_re_dict(re_template, configuration)
        if not template:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Could not read re_template %s. %s' % (re_template, msg)
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)

    # Override template fields if user loaded a template and modified the
    # required entries and chose update.
    # Use default of 1 sw, 1 env and 0 test or template setting otherwise
    if software_entries < 0:
        software_entries = len(template.get('SOFTWARE', [None]))
    if environment_entries < 0:
        environment_entries = len(template.get('ENVIRONMENTVARIABLE', [None]))
    if testprocedure_entry < 0:
        testprocedure_entry = len(template.get('TESTPROCEDURE', []))
    if template.has_key('SOFTWARE'):
        new_sw = template['SOFTWARE'][:software_entries]
        template['SOFTWARE'] = new_sw
    if template.has_key('ENVIRONMENTVARIABLE'):
        new_env = template['ENVIRONMENTVARIABLE'][:environment_entries]
        template['ENVIRONMENTVARIABLE'] = new_env
    if template.has_key('TESTPROCEDURE'):
        new_test = template['TESTPROCEDURE'][:testprocedure_entry]
        template['TESTPROCEDURE'] = new_test

    # Avoid DoS, limit number of software_entries

    if software_entries > max_software_entries:
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Maximum number of software_entries %s exceeded (%s)' % \
             (max_software_entries, software_entries)})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # Avoid DoS, limit number of environment_entries

    if environment_entries > max_environment_entries:
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Maximum number of environment_entries %s exceeded (%s)' % \
             (max_environment_entries, environment_entries)})
        return (output_objects, returnvalues.CLIENT_ERROR)

    rekeywords_dict = get_keywords_dict()
    (list_status, ret) = list_runtime_environments(configuration)
    if not list_status:
        output_objects.append({'object_type': 'error_text', 'text': ret})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    output_objects.append({
        'object_type':
        'text',
        'text':
        'Use existing Runtime Environment as template'
    })

    html_form = \
        """<form method='get' action='adminre.py'>
    <select name='re_template'>
    <option value=''>None</option>
"""
    for existing_re in ret:
        html_form += "    <option value='%s'>%s</option>\n" % \
                     (existing_re, existing_re)
    html_form += """
    </select>
    <input type='submit' value='Get' />
</form>"""
    output_objects.append({'object_type': 'html_form', 'text': html_form})

    output_objects.append({
        'object_type':
        'text',
        'text':
        '''Note that a runtime environment can not be changed after creation
and it can only be removed if not in use by any resources, so please be careful
when filling in the details'''
    })
    output_objects.append({
        'object_type':
        'text',
        'text':
        '''Changing the number of software and environment entries removes
all data in the form, so please enter the correct values before entering any
information.'''
    })

    html_form = \
        """<form method='get' action='adminre.py'>
    <table>
"""
    html_form += """
<tr>
    <td>Number of needed software entries</td>
    <td><input type='number' name='software_entries' min=0 max=99
    minlength=1 maxlength=2 value='%s' required pattern='[0-9]{1,2}'
    title='number of software entries needed in runtime environment' /></td>
</tr>""" % software_entries
    html_form += """
<tr>
    <td>Number of environment entries</td>
    <td>
    <input type='number' name='environment_entries' min=0 max=99
    minlength=1 maxlength=2 value='%s' required pattern='[0-9]{1,2}'
    title='number of environment variables provided by runtime environment' />
    </td>
</tr>""" % environment_entries
    output_objects.append({'object_type': 'html_form', 'text': html_form})
    if testprocedure_entry == 0:
        select_string = """<option value='0' selected>No</option>
<option value=1>Yes</option>"""
    elif testprocedure_entry == 1:
        select_string = """<option value='0'>No</option>
<option value='1' selected>Yes</option>"""
    else:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'testprocedure_entry should be 0 or 1, you specified %s' %
            testprocedure_entry
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    html_form = """
<tr>
    <td>Runtime environment has a testprocedure</td>
    <td><select name='testprocedure_entry'>%s</select></td>
</tr>
<tr>
    <td colspan=2>
    <input type='hidden' name='re_template' value='%s' />
    <input type='submit' value='Update fields' />
    </td>
</tr>
</table>
</form><br />
""" % (select_string, re_template)

    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 = 'createre'
    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})
    html_form += """
<form method='%(form_method)s' action='%(target_op)s.py'>
<input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' />
<b>Runtime Environment Name</b><br />
<small>(eg. BASH-2.X-1, must be unique):</small><br />
<input class='p80width' type='text' name='re_name' required 
    pattern='[a-zA-Z0-9_.-]+'
    title='unique name of ASCII letters and digits separated only by underscores, periods and hyphens' />
<br />
<br /><b>Description:</b><br />
<textarea class='p80width' rows='4' name='redescription'>
"""
    if template:
        html_form += template['DESCRIPTION'].replace('<br />', '\n')
    html_form += '</textarea><br />'

    soft_list = []
    if software_entries > 0:
        html_form += '<br /><b>Needed Software:</b><br />'
    if template:
        if template.has_key('SOFTWARE'):
            soft_list = template['SOFTWARE']
            for soft in soft_list:
                html_form += """
<textarea class='p80width' rows='6' name='software'>"""
                for keyname in soft.keys():
                    if keyname != '':
                        html_form += '%s=%s\n' % (keyname, soft[keyname])
                html_form += '</textarea><br />'

    # loop and create textareas for any missing software entries

    software = rekeywords_dict['SOFTWARE']
    sublevel_required = []
    sublevel_optional = []

    if software.has_key('Sublevel') and software['Sublevel']:
        sublevel_required = software['Sublevel_required']
        sublevel_optional = software['Sublevel_optional']

    for _ in range(len(soft_list), software_entries):
        html_form += """
<textarea class='p80width' rows='6' name='software'>"""
        for sub_req in sublevel_required:
            html_form += '%s=   # required\n' % sub_req
        for sub_opt in sublevel_optional:
            html_form += '%s=   # optional\n' % sub_opt
        html_form += '</textarea><br />'

    if template and testprocedure_entry == 1:
        if template.has_key('TESTPROCEDURE'):
            html_form += """
<br /><b>Testprocedure</b> (in mRSL format):<br />
<textarea class='p80width' rows='15' name='testprocedure'>"""

            base64string = ''
            for stringpart in template['TESTPROCEDURE']:
                base64string += stringpart
                decodedstring = base64.decodestring(base64string)
                html_form += decodedstring
            html_form += '</textarea>'
            output_objects.append({
                'object_type': 'html_form',
                'text': html_form
            })

            html_form = """
<br /><b>Expected .stdout file if testprocedure is executed</b><br />
<textarea class='p80width' rows='10' name='verifystdout'>"""

            if template.has_key('VERIFYSTDOUT'):
                for line in template['VERIFYSTDOUT']:
                    html_form += line
            html_form += '</textarea>'

            html_form += """
<br /><b>Expected .stderr file if testprocedure is executed</b><br />
<textarea cols='50' rows='10' name='verifystderr'>"""
            if template.has_key('VERIFYSTDERR'):
                for line in template['VERIFYSTDERR']:
                    html_form += line
            html_form += '</textarea>'

            html_form += """
<br /><b>Expected .status file if testprocedure is executed</b><br />
<textarea cols='50' rows='10' name='verifystatus'>"""
            if template.has_key('VERIFYSTATUS'):
                for line in template['VERIFYSTATUS']:
                    html_form += line
            html_form += '</textarea>'
    elif testprocedure_entry == 1:

        html_form += """
<br /><b>Testprocedure</b> (in mRSL format):<br />
<textarea class='p80width' rows='15' name='testprocedure'>"""

        html_form += \
            """::EXECUTE::
ls    
</textarea>
<br /><b>Expected .stdout file if testprocedure is executed</b><br />
<textarea class='p80width' rows='10' name='verifystdout'></textarea>
<br /><b>Expected .stderr file if testprocedure is executed</b><br />
<textarea class='p80width' rows='10' name='verifystderr'></textarea>
<br /><b>Expected .status file if testprocedure is executed</b><br />
<textarea class='p80width' rows='10' name='verifystatus'></textarea>
"""

    environmentvariable = rekeywords_dict['ENVIRONMENTVARIABLE']
    sublevel_required = []
    sublevel_optional = []

    if environmentvariable.has_key('Sublevel')\
         and environmentvariable['Sublevel']:
        sublevel_required = environmentvariable['Sublevel_required']
        sublevel_optional = environmentvariable['Sublevel_optional']

    env_list = []
    if environment_entries > 0:
        html_form += '<br /><b>Environments:</b><br />'
    if template:
        if template.has_key('ENVIRONMENTVARIABLE'):
            env_list = template['ENVIRONMENTVARIABLE']
            for env in env_list:
                html_form += """
<textarea class='p80width' rows='4' name='environment'>"""
                for keyname in env.keys():
                    if keyname != '':
                        html_form += '%s=%s\n' % (keyname, env[keyname])
                html_form += '</textarea><br />'

    # loop and create textareas for any missing environment entries

    for _ in range(len(env_list), environment_entries):
        html_form += """
<textarea class='p80width' rows='4' name='environment'>"""
        for sub_req in sublevel_required:
            html_form += '%s=   # required\n' % sub_req
        for sub_opt in sublevel_optional:
            html_form += '%s=   # optional\n' % sub_opt
        html_form += '</textarea><br />'

    html_form += """<br /><br /><input type='submit' value='Create' />
    </form>
"""
    output_objects.append({
        'object_type': 'html_form',
        'text': html_form % fill_helpers
    })
    return (output_objects, returnvalues.OK)
Beispiel #2
0
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)
Beispiel #3
0
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)

    hosturl = accepted['hosturl'][-1]
    hostidentifier = accepted['hostidentifier'][-1]
    resource_id = '%s.%s' % (hosturl, hostidentifier)
    extra_selects = 3

    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)

    # Find allowed VGrids and Runtimeenvironments and add them to
    # configuration object for automated choice handling

    allowed_vgrids = [''] + res_vgrid_access(configuration, resource_id)
    allowed_vgrids.sort()

    configuration.vgrids = allowed_vgrids
    (re_status, allowed_run_envs) = list_runtime_environments(configuration)
    allowed_run_envs.sort()
    area_cols = 80
    area_rows = 5

    status = returnvalues.OK

    logger.info('Starting Resource edit GUI.')

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'Resource Editor'
    output_objects.append({'object_type': 'header', 'text': 'Resource Editor'})
    output_objects.append({
        'object_type':
        'sectionheader',
        'text':
        '%s Resource Editor' % configuration.short_title
    })
    output_objects.append({
        'object_type':
        'text',
        'text':
        '''
Please fill in or edit the fields below to fit your %s resource reservation. Most fields
will work with their default values. So if you are still in doubt after reading the help
description, you can likely just leave the field alone.''' %
        configuration.short_title
    })

    if hosturl and hostidentifier:
        conf = init_conf(configuration, hosturl, hostidentifier)
        if not conf:
            status = returnvalues.CLIENT_ERROR
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                '''No such resource! (%s.%s)''' % (hosturl, hostidentifier)
            })
            return (output_objects, status)
    else:
        conf = empty_resource_config(configuration)

    res_fields = resconfkeywords.get_resource_specs(configuration)
    exe_fields = resconfkeywords.get_exenode_specs(configuration)
    store_fields = resconfkeywords.get_storenode_specs(configuration)

    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 = 'reseditaction'
    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' />
""" % fill_helpers
    })

    # Resource overall fields

    output_objects.append({
        'object_type': 'sectionheader',
        'text': "Main Resource Settings"
    })
    output_objects.append({
        'object_type':
        'text',
        'text':
        """This section configures general options for the resource."""
    })

    (title, field) = ('Host FQDN', 'HOSTURL')
    if hosturl:
        try:
            hostip = conf.get('HOSTIP', socket.gethostbyname(hosturl))
        except:
            hostip = '<unknown>'
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            """<br />
<b>%s:</b>&nbsp;<a class='infolink iconspace' href='resedithelp.py#res-%s'>help</a><br />
<input type='hidden' name='%s' value='%s' />
<input type='hidden' name='hostip' value='%s' />
%s
<br />
<br />""" % (title, field, field, conf[field], hostip, conf[field])
        })
    else:
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            """<br />
<b>%s:</b>&nbsp;<a class='infolink iconspace' href='resedithelp.py#res-%s'>help</a><br />
<input class='fillwidth padspace' type='text' name='%s' size='%d' value='%s'
    required pattern='[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)+'
    title='Fully qualified domain name or Internet IP address of the resource'
/>
<br />
<br />""" % (title, field, field, field_size(conf[field]), conf[field])
        })

    (title, field) = ('Host identifier', 'HOSTIDENTIFIER')
    if hostidentifier:
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            """<br />
<b>%s:</b>&nbsp;<a class='infolink iconspace' href='resedithelp.py#res-%s'>help</a><br />
<input type='hidden' name='%s' value='%s' />
%s
<br />
<br />""" % (title, field, field, conf[field], conf[field])
        })

    (field, title) = 'frontendhome', 'Frontend Home Path'
    output_objects.append({
        'object_type':
        'html_form',
        'text':
        """<br />
<b>%s:</b>&nbsp;<a class='infolink iconspace' href='resedithelp.py#%s'>help</a><br />
<input class='fillwidth padspace' type='text' name='%s' size='%d' value='%s'
    required pattern='[^ ]+' title='Absolute path to user home on the resource'
/>
<br />
<br />""" % (title, field, field, field_size(conf[field]), conf[field])
    })

    for (field, spec) in res_fields:
        title = spec['Title']
        field_type = spec['Type']
        if spec['Required']:
            required_str = 'required'
        else:
            required_str = ''

        if 'invisible' == spec['Editor']:
            continue
        elif 'input' == spec['Editor']:
            if spec['Type'] == 'int':
                input_str = """
<input class='fillwidth padspace' type='number' name='%s' size='%d' value='%s'
    min=0 pattern='[0-9]+' %s />
""" % (field, field_size(conf[field]), conf[field], required_str)
            else:
                input_str = """
<input class='fillwidth padspace' type='text' name='%s' size='%d' value='%s'
    %s />
""" % (field, field_size(conf[field]), conf[field], required_str)
            output_objects.append({
                'object_type':
                'html_form',
                'text':
                """<br />
<b>%s:</b>&nbsp;<a class='infolink iconspace' href='resedithelp.py#res-%s'>help</a>
<br />
%s<br />
<br />""" % (title, field, input_str)
            })
        elif 'select' == spec['Editor']:
            choices = available_choices(configuration, client_id, resource_id,
                                        field, spec)
            res_value = conf[field]
            value_select = ''
            if field_type.startswith('multiple'):
                select_count = len(res_value) + extra_selects
            else:
                select_count = 1
                res_value = [res_value]
            for i in range(select_count):
                value_select += "<select name='%s'>\n" % field
                for name in choices:
                    selected = ''
                    if i < len(res_value) and res_value[i] == name:
                        selected = 'selected'
                    display = "%s" % name
                    if display == '':
                        display = ' '
                    value_select += """<option %s value='%s'>%s</option>\n""" \
                                    % (selected, name, display)
                value_select += """</select><br />\n"""
            output_objects.append({
                'object_type':
                'html_form',
                'text':
                """<br />
<b>%s:</b>&nbsp;<a class='infolink iconspace' href='resedithelp.py#res-%s'>help</a><br />
%s
<br />""" % (title, field, value_select)
            })

    # Not all resource fields here map directly to keywords/specs input field

    (title, field) = ('Runtime Environments', 'RUNTIMEENVIRONMENT')
    re_list = conf[field]
    show = re_list + [('', []) for i in range(extra_selects)]
    re_select = "<input type='hidden' name='runtime_env_fields' value='%s'/>\n" \
                % len(show)
    i = 0
    for active in show:
        re_select += "<select name='runtimeenvironment%d'>\n" % i
        for name in allowed_run_envs + ['']:
            selected = ''
            if active[0] == name:
                selected = 'selected'
            display = "%s" % name
            if display == '':
                display = ' '
            re_select += """<option %s value='%s'>%s</option>\n""" % \
                         (selected, name, display)
        re_select += """</select><br />\n"""
        values = '\n'.join(['%s=%s' % pair for pair in active[1]])
        re_select += "<textarea class='fillwidth padspace' cols='%d' rows='%d' name='re_values%d'>%s</textarea><br />\n" % \
                     (area_cols, area_rows, i, values)
        i += 1

    output_objects.append({
        'object_type':
        'html_form',
        'text':
        """<br />
<b>%s:</b>&nbsp;<a class='infolink iconspace' href='resedithelp.py#res-%s'>help</a><br />
Please enter any required environment variable settings on the form NAME=VALUE in the box below
each selected runtimeenvironment.<br />
%s
<br />""" % (title, field, re_select)
    })

    # Execution node fields

    output_objects.append({
        'object_type': 'sectionheader',
        'text': "Execution nodes"
    })
    output_objects.append({
        'object_type':
        'text',
        'text':
        """This section configures execution nodes on the resource."""
    })
    (field, title) = 'executionnodes', 'Execution Node(s)'
    output_objects.append({
        'object_type':
        'html_form',
        'text':
        """<br />
<b>%s:</b>&nbsp;<a class='infolink iconspace' href='resedithelp.py#exe-%s'>help</a><br />
<input class='fillwidth padspace' type='text' name='exe-%s' size='%d' value='%s' />
<br />
<br />""" % (title, field, field, field_size(
            conf['all_exes'][field]), conf['all_exes'][field])
    })

    (field, title) = 'executionhome', 'Execution Home Path'
    output_objects.append({
        'object_type':
        'html_form',
        'text':
        """<br />
<b>%s:</b>&nbsp;<a class='infolink iconspace' href='resedithelp.py#exe-%s'>help</a><br />
<input class='fillwidth padspace' type='text' name='exe-%s' size='%d' value='%s' />
<br />
<br />""" % (title, field, field, field_size(
            conf['all_exes'][field]), conf['all_exes'][field])
    })

    for (field, spec) in exe_fields:
        title = spec['Title']
        field_type = spec['Type']
        # We don't really have a good map of required fields here so disable
        required_str = ''
        if 'invisible' == spec['Editor']:
            continue
        elif 'input' == spec['Editor']:
            if spec['Type'] == 'int':
                input_str = """
<input class='fillwidth padspace' type='number' name='exe-%s' size='%d' value='%s'
    min=0 pattern='[0-9]+' %s />
""" % (field, field_size(conf['all_exes'][field]), conf['all_exes'][field],
                required_str)
            else:
                input_str = """
<input class='fillwidth padspace' type='text' name='exe-%s' size='%d' value='%s'
    %s />
""" % (field, field_size(conf['all_exes'][field]), conf['all_exes'][field],
                required_str)

            output_objects.append({
                'object_type':
                'html_form',
                'text':
                """<br />
<b>%s:</b>&nbsp;<a class='infolink iconspace' href='resedithelp.py#exe-%s'>help</a>
<br />
%s
<br />
<br />""" % (title, field, input_str)
            })
        elif 'select' == spec['Editor']:
            choices = available_choices(configuration, client_id, resource_id,
                                        field, spec)
            exe_value = conf['all_exes'][field]
            value_select = ''
            if field_type.startswith('multiple'):
                select_count = len(exe_value) + extra_selects
            else:
                select_count = 1
                exe_value = [exe_value]
            for i in range(select_count):
                value_select += "<select name='exe-%s'>\n" % field
                for name in choices:
                    selected = ''
                    if i < len(exe_value) and exe_value[i] == name:
                        selected = 'selected'
                    display = "%s" % name
                    if display == '':
                        display = ' '
                    value_select += """<option %s value='%s'>%s</option>\n""" \
                                    % (selected, name, display)
                value_select += """</select><br />\n"""
            output_objects.append({
                'object_type':
                'html_form',
                'text':
                """<br />
<b>%s:</b>&nbsp;<a class='infolink iconspace' href='resedithelp.py#exe-%s'>help</a><br />
%s
<br />""" % (title, field, value_select)
            })

    # Storage node fields

    output_objects.append({
        'object_type': 'sectionheader',
        'text': "Storage nodes"
    })
    output_objects.append({
        'object_type':
        'text',
        'text':
        """This section configures storage nodes on the resource."""
    })

    (field, title) = 'storagenodes', 'Storage Node(s)'
    output_objects.append({
        'object_type':
        'html_form',
        'text':
        """<br />
<b>%s:</b>&nbsp;<a class='infolink iconspace' href='resedithelp.py#store-%s'>help</a><br />
<input class='fillwidth padspace' type='text' name='store-%s' size='%d' value='%s' />
<br />
<br />""" % (title, field, field, field_size(
            conf['all_stores'][field]), conf['all_stores'][field])
    })

    (field, title) = 'storagehome', 'Storage Home Path'
    output_objects.append({
        'object_type':
        'html_form',
        'text':
        """<br />
<b>%s:</b>&nbsp;<a class='infolink iconspace' href='resedithelp.py#store-%s'>help</a><br />
<input class='fillwidth padspace' type='text' name='store-%s' size='%d' value='%s' />
<br />
<br />""" % (title, field, field, field_size(
            conf['all_stores'][field]), conf['all_stores'][field])
    })

    for (field, spec) in store_fields:
        title = spec['Title']
        field_type = spec['Type']
        # We don't really have a good map of required fields here so disable
        required_str = ''
        if 'invisible' == spec['Editor']:
            continue
        elif 'input' == spec['Editor']:
            if spec['Type'] == 'int':
                input_str = """
<input class='fillwidth padspace' type='number' name='store-%s' size='%d' value='%s'
    min=0 pattern='[0-9]+' %s />
""" % (field, field_size(conf['all_stores'][field]), conf['all_stores'][field],
                required_str)
            else:
                input_str = """
<input class='fillwidth padspace' type='text' name='store-%s' size='%d' value='%s'
    %s />
""" % (field, field_size(conf['all_stores'][field]), conf['all_stores'][field],
                required_str)

            output_objects.append({
                'object_type':
                'html_form',
                'text':
                """<br />
<b>%s:</b>&nbsp;<a class='infolink iconspace' href='resedithelp.py#store-%s'>help</a>
<br />
%s
<br />
<br />""" % (title, field, input_str)
            })
        elif 'select' == spec['Editor']:
            choices = available_choices(configuration, client_id, resource_id,
                                        field, spec)
            store_value = conf['all_stores'][field]
            value_select = ''
            if field_type.startswith('multiple'):
                select_count = len(store_value) + extra_selects
            else:
                select_count = 1
                store_value = [store_value]
            for i in range(select_count):
                value_select += "<select name='store-%s'>\n" % field
                for name in choices:
                    selected = ''
                    if i < len(store_value) and store_value[i] == name:
                        selected = 'selected'
                    display = "%s" % name
                    if display == '':
                        display = ' '
                    value_select += """<option %s value='%s'>%s</option>\n""" \
                                    % (selected, name, display)
                value_select += """</select><br />\n"""
            output_objects.append({
                'object_type':
                'html_form',
                'text':
                """<br />
<b>%s:</b>&nbsp;<a class='infolink iconspace' href='resedithelp.py#store-%s'>help</a><br />
%s
<br />""" % (title, field, value_select)
            })

    output_objects.append({
        'object_type':
        'html_form',
        'text':
        """
<input type='submit' value='Save' />
</form>
"""
    })

    return (output_objects, status)
Beispiel #4
0
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)
    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_description = accepted['description'][-1].lower() == 'true'

    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)

    # 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

    template_path = os.path.join(base_dir, default_mrsl_filename)

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'Submit Job'
    user_settings = title_entry.get('user_settings', {})
    output_objects.append({'object_type': 'header', 'text': 'Submit Job'})
    default_mrsl = get_default_mrsl(template_path)
    if not user_settings or not user_settings.has_key('SUBMITUI'):
        logger.info('Settings dict does not have SUBMITUI key - using default')
        submit_style = configuration.submitui[0]
    else:
        submit_style = user_settings['SUBMITUI']

    # We generate all 3 variants of job submission (fields, textarea, files),
    # initially hide them and allow to switch between them using js.

    # could instead extract valid prefixes as in settings.py
    # (means: by "eval" from configuration). We stick to hard-coding.
    submit_options = ['fields_form', 'textarea_form', 'files_form']

    open_button_id = 'open_fancy_upload'
    form_method = 'post'
    csrf_limit = get_csrf_limit(configuration)
    fill_helpers = {
        'dest_dir': '.' + os.sep,
        'fancy_open': open_button_id,
        'default_mrsl': default_mrsl,
        'form_method': form_method,
        'csrf_field': csrf_field,
        'csrf_limit': csrf_limit
    }
    target_op = 'uploadchunked'
    csrf_token = make_csrf_token(configuration, form_method, target_op,
                                 client_id, csrf_limit)
    (add_import, add_init, add_ready) = fancy_upload_js(configuration,
                                                        csrf_token=csrf_token)
    add_init += '''
    submit_options = %s;

    function setDisplay(this_id, new_d) {
        //console.log("setDisplay with: "+this_id);
        el = document.getElementById(this_id)
        if (el == undefined || el.style == undefined) {
            console.log("failed to locate display element: "+this_id);
            return; // avoid js null ref errors
        }
        el.style.display=new_d;
    }

    function switchTo(name) {
        //console.log("switchTo: "+name);
        for (o=0; o < submit_options.length; o++) {
            if (name == submit_options[o]) {
                setDisplay(submit_options[o],"block");
            } else {
                setDisplay(submit_options[o],"none");
            }
        }
    }
    ''' % submit_options
    add_ready += '''
    switchTo("%s");
    setUploadDest("%s");
    /* wrap openFancyUpload in function to avoid event data as argument */
    $("#%s").click(function() { openFancyUpload(); });
    ''' % (submit_style + "_form", fill_helpers['dest_dir'], open_button_id)
    fancy_dialog = fancy_upload_html(configuration)
    # TODO: can we update style inline to avoid explicit themed_styles?
    title_entry['style'] = themed_styles(
        configuration,
        base=['jquery.fileupload.css', 'jquery.fileupload-ui.css'],
        skin=['fileupload-ui.custom.css'],
        user_settings=user_settings)
    title_entry['script']['advanced'] += add_import
    title_entry['script']['init'] += add_init
    title_entry['script']['ready'] += add_ready

    output_objects.append({
        'object_type':
        'text',
        'text':
        'This page is used to submit jobs to the grid.'
    })

    output_objects.append({
        'object_type':
        'verbatim',
        'text':
        '''
There are %s interface styles available that you can choose among:''' %
        len(submit_options)
    })

    links = []
    for opt in submit_options:
        name = opt.split('_', 2)[0]
        links.append({
            'object_type': 'link',
            'destination': "javascript:switchTo('%s')" % opt,
            'class': 'submit%slink iconspace' % name,
            'title': 'Switch to %s submit interface' % name,
            'text': '%s style' % name,
        })
    output_objects.append({'object_type': 'multilinkline', 'links': links})

    output_objects.append({
        'object_type':
        'text',
        'text':
        '''
Please note that changes to the job description are *not* automatically
transferred if you switch style.'''
    })

    output_objects.append({
        'object_type':
        'html_form',
        'text':
        '<div id="fields_form" style="display:none;">\n'
    })

    # Fields
    output_objects.append({
        'object_type':
        'sectionheader',
        'text':
        'Please fill in your job description in the fields'
        ' below:'
    })
    output_objects.append({
        'object_type':
        'text',
        'text':
        """
Please fill in one or more fields below to define your job before hitting
Submit Job at the bottom of the page.
Empty fields will simply result in the default value being used and each field
is accompanied by a help link providing further details about the field."""
    })

    fill_helpers.update({'fancy_dialog': fancy_dialog})
    target_op = 'submitfields'
    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':
        """
<div class='submitjob'>
<form method='%(form_method)s' action='%(target_op)s.py'> 
<input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' />
""" % fill_helpers
    })
    show_fields = get_job_specs(configuration)
    try:
        parsed_mrsl = dict(parse_lines(default_mrsl))
    except:
        parsed_mrsl = {}

    # Find allowed VGrids and Runtimeenvironments and add them to
    # configuration object for automated choice handling

    vgrid_access = user_vgrid_access(configuration, client_id) + \
        [any_vgrid]
    vgrid_access.sort()
    configuration.vgrids = vgrid_access
    (re_status, allowed_run_envs) = list_runtime_environments(configuration)
    if not re_status:
        logger.error('Failed to extract allowed runtime envs: %s' %
                     allowed_run_envs)
        allowed_run_envs = []
    allowed_run_envs.sort()
    configuration.runtimeenvironments = allowed_run_envs
    # TODO: next call is slow because we walk and reload all pickles
    user_res = user_allowed_res_exes(configuration, client_id)

    # Add valid MAXFILL values to automated choice handling

    configuration.maxfills = [keyword_all] + maxfill_fields

    # Allow any exe unit on all allowed resources

    allowed_resources = ['%s_*' % res for res in user_res.keys()]
    allowed_resources.sort()
    configuration.resources = allowed_resources
    field_size = 30
    area_cols = 80
    area_rows = 5

    for (field, spec) in show_fields:
        title = spec['Title']
        if show_description:
            description = '%s<br />' % spec['Description']
        else:
            description = ''
        field_type = spec['Type']
        # Use saved value and fall back to default if it is missing
        saved = parsed_mrsl.get('::%s::' % field, None)
        if saved:
            if not spec['Type'].startswith('multiple'):
                default = saved[0]
            else:
                default = saved
        else:
            default = spec['Value']
        # Hide sandbox field if sandboxes are disabled
        if field == 'SANDBOX' and not configuration.site_enable_sandboxes:
            continue
        if 'invisible' == spec['Editor']:
            continue
        if 'custom' == spec['Editor']:
            continue
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            """
<b>%s:</b>&nbsp;<a class='infolink iconspace' href='docs.py?show=job#%s'>
help</a><br />
%s""" % (title, field, description)
        })

        if 'input' == spec['Editor']:
            if field_type.startswith('multiple'):
                output_objects.append({
                    'object_type':
                    'html_form',
                    'text':
                    """
<textarea class='fillwidth padspace' name='%s' cols='%d' rows='%d'>%s</textarea><br />
""" % (field, area_cols, area_rows, '\n'.join(default))
                })
            elif field_type == 'int':
                output_objects.append({
                    'object_type':
                    'html_form',
                    'text':
                    """
<input type='number' name='%s' size='%d' value='%s' min=0 required pattern='[0-9]+' /><br />
""" % (field, field_size, default)
                })
            else:
                output_objects.append({
                    'object_type':
                    'html_form',
                    'text':
                    """
<input type='text' name='%s' size='%d' value='%s' /><br />
""" % (field, field_size, default)
                })
        elif 'select' == spec['Editor']:
            choices = available_choices(configuration, client_id, field, spec)
            res_value = default
            value_select = ''
            if field_type.startswith('multiple'):
                value_select += '<div class="scrollselect">'
                for name in choices:
                    # Blank default value does not make sense here
                    if not str(name):
                        continue
                    selected = ''
                    if str(name) in res_value:
                        selected = 'checked'
                    value_select += '''
                        <input type="checkbox" name="%s" %s value=%s>%s<br />
                        ''' % (field, selected, name, name)
                value_select += '</div>\n'
            else:
                value_select += "<select name='%s'>\n" % field
                for name in choices:
                    selected = ''
                    if str(res_value) == str(name):
                        selected = 'selected'
                    display = "%s" % name
                    if display == '':
                        display = ' '
                    value_select += """<option %s value='%s'>%s</option>\n""" \
                                    % (selected, name, display)
                value_select += """</select><br />\n"""
            output_objects.append({
                'object_type': 'html_form',
                'text': value_select
            })
        output_objects.append({'object_type': 'html_form', 'text': "<br />"})

    output_objects.append({
        'object_type':
        'html_form',
        'text':
        """
<br />
<table class='centertext'>
<tr><td><input type='submit' value='Submit Job' />
<input type='checkbox' name='save_as_default'> Save as default job template
</td></tr>
</table>
<br />
</form>
</div>
"""
    })
    output_objects.append({
        'object_type':
        'html_form',
        'text':
        '''
</div><!-- fields_form-->
<div id="textarea_form" style="display:none;">
'''
    })

    # Textarea
    output_objects.append({
        'object_type':
        'sectionheader',
        'text':
        'Please enter your mRSL job description below:'
    })
    output_objects.append({
        'object_type':
        'html_form',
        'text':
        """
<div class='smallcontent'>
Job descriptions can use a wide range of keywords to specify job requirements
and actions.<br />
Each keyword accepts one or more values of a particular type.<br />
The full list of keywords with their default values and format is available in
the on-demand <a href='docs.py?show=job'>mRSL Documentation</a>.
<p>
Actual examples for inspiration:
<a href=/public/cpuinfo.mRSL>CPU Info</a>,
<a href=/public/basic-io.mRSL>Basic I/O</a>,
<a href=/public/notification.mRSL>Job Notification</a>,
<a href=/public/povray.mRSL>Povray</a> and
<a href=/public/vcr.mRSL>VCR</a>
</div>
    """
    })

    target_op = 'textarea'
    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':
        """
<!-- 
Please note that textarea.py chokes if no nonempty KEYWORD_X_Y_Z fields 
are supplied: thus we simply send a bogus jobname which does nothing
-->
<form method='%(form_method)s' action='%(target_op)s.py'> 
<input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' />
<table class='submitjob'>
<tr><td class='centertext'>
<input type=hidden name=jobname_0_0_0 value=' ' />
<textarea class='fillwidth padspace' rows='25' name='mrsltextarea_0'>
%(default_mrsl)s
</textarea>
</td></tr>
<tr><td class='centertext'>
<input type='submit' value='Submit Job' />
<input type='checkbox' name='save_as_default' >Save as default job template
</td></tr>
</table>
</form>
""" % fill_helpers
    })

    output_objects.append({
        'object_type':
        'html_form',
        'text':
        '''
</div><!-- textarea_form-->
<div id="files_form" style="display:none;">
'''
    })
    # Upload form

    output_objects.append({
        'object_type':
        'sectionheader',
        'text':
        'Please upload your job file or packaged job files'
        ' below:'
    })
    output_objects.append({
        'object_type':
        'html_form',
        'text':
        """
<form enctype='multipart/form-data' method='%(form_method)s'
    action='%(target_op)s.py'> 
<input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' />
<table class='files'>
<tr class='title'><td class='centertext' colspan=4>
Upload job files
</td></tr>
<tr><td colspan=3>
Upload file to current directory (%(dest_dir)s)
</td><td><br /></td></tr>
<tr><td colspan=2>
Extract package files (.zip, .tar.gz, .tar.bz2)
</td><td colspan=2>
<input type=checkbox name='extract_0' />
</td></tr>
<tr><td colspan=2>
Submit mRSL files (also .mRSL files included in packages)
</td><td colspan=2>
<input type=checkbox name='submitmrsl_0' checked />
</td></tr>
<tr><td>    
File to upload
</td><td class='righttext' colspan=3>
<input name='fileupload_0_0_0' type='file'/>
</td></tr>
<tr><td>
Optional remote filename (extra useful in windows)
</td><td class='righttext' colspan=3>
<input name='default_remotefilename_0' type='hidden' value='%(dest_dir)s'/>
<input name='remotefilename_0' type='text' size='50' value='%(dest_dir)s'/>
<input type='submit' value='Upload' name='sendfile'/>
</td></tr>
</table>
</form>
<table class='files'>
<tr class='title'><td class='centertext'>
Upload other files efficiently (using chunking).
</td></tr>
<tr><td class='centertext'>
<button id='%(fancy_open)s'>Open Upload dialog</button>
</td></tr>
</table>
</div><!-- files_form-->

%(fancy_dialog)s
""" % fill_helpers
    })

    return (output_objects, status)
Beispiel #5
0
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": "Create runtime environment"})
    (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_template = accepted["re_template"][-1].upper().strip()
    software_entries = int(accepted["software_entries"][-1])
    environment_entries = int(accepted["environment_entries"][-1])
    testprocedure_entry = int(accepted["testprocedure_entry"][-1])

    template = {}
    if re_template:
        if not is_runtime_environment(re_template, configuration):
            output_objects.append(
                {
                    "object_type": "error_text",
                    "text": "re_template ('%s') is not a valid existing runtime env!" % re_template,
                }
            )
            return (output_objects, returnvalues.CLIENT_ERROR)

        (template, msg) = get_re_dict(re_template, configuration)
        if not template:
            output_objects.append(
                {"object_type": "error_text", "text": "Could not read re_template %s. %s" % (re_template, msg)}
            )
            return (output_objects, returnvalues.SYSTEM_ERROR)

    # Override template fields if user loaded a template and modified the
    # required entries and chose update.
    # Use default of 1 sw, 1 env and 0 test or template setting otherwise
    if software_entries < 0:
        software_entries = len(template.get("SOFTWARE", [None]))
    if environment_entries < 0:
        environment_entries = len(template.get("ENVIRONMENTVARIABLE", [None]))
    if testprocedure_entry < 0:
        testprocedure_entry = len(template.get("TESTPROCEDURE", []))
    if template.has_key("SOFTWARE"):
        new_sw = template["SOFTWARE"][:software_entries]
        template["SOFTWARE"] = new_sw
    if template.has_key("ENVIRONMENTVARIABLE"):
        new_env = template["ENVIRONMENTVARIABLE"][:environment_entries]
        template["ENVIRONMENTVARIABLE"] = new_env
    if template.has_key("TESTPROCEDURE"):
        new_test = template["TESTPROCEDURE"][:testprocedure_entry]
        template["TESTPROCEDURE"] = new_test

    # Avoid DoS, limit number of software_entries

    if software_entries > max_software_entries:
        output_objects.append(
            {
                "object_type": "error_text",
                "text": "Maximum number of software_entries %s exceeded (%s)"
                % (max_software_entries, software_entries),
            }
        )
        return (output_objects, returnvalues.CLIENT_ERROR)

    # Avoid DoS, limit number of environment_entries

    if environment_entries > max_environment_entries:
        output_objects.append(
            {
                "object_type": "error_text",
                "text": "Maximum number of environment_entries %s exceeded (%s)"
                % (max_environment_entries, environment_entries),
            }
        )
        return (output_objects, returnvalues.CLIENT_ERROR)

    rekeywords_dict = get_keywords_dict()
    (status, ret) = list_runtime_environments(configuration)
    if not status:
        output_objects.append({"object_type": "error_text", "text": ret})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    output_objects.append({"object_type": "text", "text": "Use existing RE as template"})

    html_form = """<form method='get' action='adminre.py'>
    <select name='re_template'>
    <option value=''>None</option>
"""
    for existing_re in ret:
        html_form += "    <option value='%s'>%s</option>\n" % (existing_re, existing_re)
    html_form += """
    </select>
    <input type='submit' value='Get' />
</form>"""
    output_objects.append({"object_type": "html_form", "text": html_form})

    output_objects.append(
        {
            "object_type": "text",
            "text": """Note that a runtime environment can not be changed after creation
and it can only be removed if not in use by any resources, so please be careful
when filling in the details""",
        }
    )
    output_objects.append(
        {
            "object_type": "text",
            "text": """Changing the number of software and environment entries removes
all data in the form, so please enter the correct values before entering any
information.""",
        }
    )

    html_form = """<form method='get' action='adminre.py'>
    <table>
"""
    html_form += (
        """
<tr>
    <td>Number of needed software entries</td>
    <td><input type='text' size='2' name='software_entries' value='%s' /></td>
</tr>"""
        % software_entries
    )
    html_form += (
        """
<tr>
    <td>Number of environment entries</td>
    <td>
    <input type='text' size='2' name='environment_entries' value='%s' />
    </td>
</tr>"""
        % environment_entries
    )
    output_objects.append({"object_type": "html_form", "text": html_form})
    if testprocedure_entry == 0:
        select_string = """<option value='0' selected>No</option>
<option value=1>Yes</option>"""
    elif testprocedure_entry == 1:
        select_string = """<option value='0'>No</option>
<option value='1' selected>Yes</option>"""
    else:
        output_objects.append(
            {
                "object_type": "error_text",
                "text": "testprocedure_entry should be 0 or 1, you specified %s" % testprocedure_entry,
            }
        )
        return (output_objects, returnvalues.CLIENT_ERROR)

    html_form = """
<tr>
    <td>Runtime environment has a testprocedure</td>
    <td><select name='testprocedure_entry'>%s</select></td>
</tr>
<tr>
    <td colspan=2>
    <input type='hidden' name='re_template' value='%s' />
    <input type='submit' value='Update fields' />
    </td>
</tr>
</table>
</form><br />
""" % (
        select_string,
        re_template,
    )

    html_form += """
<form method='post' action='createre.py'>
<b>RE Name</b><br />
<small>(eg. BASH-2.X-1, must be unique):</small><br />
<input type='text' size='40' name='re_name' /><br />
<br /><b>Description:</b><br />
<textarea cols='50' rows='2' name='redescription'>
"""
    if template:
        html_form += template["DESCRIPTION"].replace("<br />", "\n")
    html_form += "</textarea><br />"

    soft_list = []
    if software_entries > 0:
        html_form += "<br /><b>Needed Software:</b><br />"
    if template:
        if template.has_key("SOFTWARE"):
            soft_list = template["SOFTWARE"]
            for soft in soft_list:
                html_form += """
<textarea cols='50' rows='5' name='software'>"""
                for keyname in soft.keys():
                    if keyname != "":
                        html_form += "%s=%s\n" % (keyname, soft[keyname])
                html_form += "</textarea><br />"

    # loop and create textareas for any missing software entries

    software = rekeywords_dict["SOFTWARE"]
    sublevel_required = []
    sublevel_optional = []

    if software.has_key("Sublevel") and software["Sublevel"]:
        sublevel_required = software["Sublevel_required"]
        sublevel_optional = software["Sublevel_optional"]

    for _ in range(len(soft_list), software_entries):
        html_form += """
<textarea cols='50' rows='5' name='software'>"""
        for sub_req in sublevel_required:
            html_form += "%s=   # required\n" % sub_req
        for sub_opt in sublevel_optional:
            html_form += "%s=   # optional\n" % sub_opt
        html_form += "</textarea><br />"

    if template and testprocedure_entry == 1:
        if template.has_key("TESTPROCEDURE"):
            html_form += """
<br /><b>Testprocedure</b> (in mRSL format):<br />
<textarea cols='50' rows='15' name='testprocedure'>"""

            base64string = ""
            for stringpart in template["TESTPROCEDURE"]:
                base64string += stringpart
                decodedstring = base64.decodestring(base64string)
                html_form += decodedstring
            html_form += "</textarea>"
            output_objects.append({"object_type": "html_form", "text": html_form})

            html_form = """
<br /><b>Expected .stdout file if testprocedure is executed</b><br />
<textarea cols='50' rows='10' name='verifystdout'>"""

            if template.has_key("VERIFYSTDOUT"):
                for line in template["VERIFYSTDOUT"]:
                    html_form += line
            html_form += "</textarea>"

            html_form += """
<br /><b>Expected .stderr file if testprocedure is executed</b><br />
<textarea cols='50' rows='10' name='verifystderr'>"""
            if template.has_key("VERIFYSTDERR"):
                for line in template["VERIFYSTDERR"]:
                    html_form += line
            html_form += "</textarea>"

            html_form += """
<br /><b>Expected .status file if testprocedure is executed</b><br />
<textarea cols='50' rows='10' name='verifystatus'>"""
            if template.has_key("VERIFYSTATUS"):
                for line in template["VERIFYSTATUS"]:
                    html_form += line
            html_form += "</textarea>"
    elif testprocedure_entry == 1:

        html_form += """
<br /><b>Testprocedure</b> (in mRSL format):<br />
<textarea cols='50' rows='15' name='testprocedure'>"""

        html_form += """::EXECUTE::
ls    
</textarea>
<br /><b>Expected .stdout file if testprocedure is executed</b><br />
<textarea cols='50' rows='10' name='verifystdout'></textarea>
<br /><b>Expected .stderr file if testprocedure is executed</b><br />
<textarea cols='50' rows='10' name='verifystderr'></textarea>
<br /><b>Expected .status file if testprocedure is executed</b><br />
<textarea cols='50' rows='10' name='verifystatus'></textarea>
"""

    environmentvariable = rekeywords_dict["ENVIRONMENTVARIABLE"]
    sublevel_required = []
    sublevel_optional = []

    if environmentvariable.has_key("Sublevel") and environmentvariable["Sublevel"]:
        sublevel_required = environmentvariable["Sublevel_required"]
        sublevel_optional = environmentvariable["Sublevel_optional"]

    env_list = []
    if environment_entries > 0:
        html_form += "<br /><b>Environments:</b><br />"
    if template:
        if template.has_key("ENVIRONMENTVARIABLE"):
            env_list = template["ENVIRONMENTVARIABLE"]
            for env in env_list:
                html_form += """
<textarea cols='50' rows='3' name='environment'>"""
                for keyname in env.keys():
                    if keyname != "":
                        html_form += "%s=%s\n" % (keyname, env[keyname])

                html_form += "</textarea><br />"

    # loop and create textareas for any missing environment entries

    for _ in range(len(env_list), environment_entries):
        html_form += """
<textarea cols='50' rows='3' name='environment'>"""
        for sub_req in sublevel_required:
            html_form += "%s=   # required\n" % sub_req
        for sub_opt in sublevel_optional:
            html_form += "%s=   # optional\n" % sub_opt
        html_form += "</textarea><br />"

    html_form += """<br /><br /><input type='submit' value='Create' />
    </form>
"""
    output_objects.append({"object_type": "html_form", "text": html_form})
    return (output_objects, returnvalues.OK)
Beispiel #6
0
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'] = 'Runtime Environments'
    (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)

    # 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. 2 (admin), then 0 (name)
          var sortOrder = [[2,1],[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;
          }

          $("#runtimeenvtable").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'
                          : 'Runtime Environments'})

    output_objects.append(
        {'object_type': 'text', 'text' :
         'Runtime environments specify software/data available on resources.'
         })
    output_objects.append(
        {'object_type': 'link',
         'destination': 'docs.py?show=Runtime+Environments',
         'class': 'infolink',
         'title': 'Show information about runtime environment',
         'text': 'Documentation on runtime environments'})

    output_objects.append({'object_type': 'sectionheader', 'text'
                          : 'Existing runtime environments'})

    (status, ret) = list_runtime_environments(configuration)
    if not status:
        output_objects.append({'object_type': 'error_text', 'text'
                              : ret})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    runtimeenvironments = []
    for single_re in ret:
        (re_dict, msg) = get_re_dict(single_re, configuration)
        if not re_dict:
            output_objects.append({'object_type': 'error_text', 'text'
                                  : msg})
            return (output_objects, returnvalues.SYSTEM_ERROR)
        re_item = build_reitem_object(configuration, re_dict)
        re_name = re_item['name']
        
        re_item['viewruntimeenvlink'] = {'object_type': 'link',
                                         'destination': "showre.py?re_name=%s" % re_name,
                                         'class': 'infolink',
                                         'title': 'View %s runtime environment' % re_name, 
                                         'text': ''}
        if client_id == re_item['creator']:
            js_name = 'delete%s' % hexlify(re_name)
            helper = html_post_helper(js_name, 'deletere.py',
                                      {'re_name': re_name})
            output_objects.append({'object_type': 'html_form', 'text': helper})
            re_item['ownerlink'] = {'object_type': 'link',
                                    'destination':
                                    "javascript: confirmDialog(%s, '%s');"\
                                    % (js_name, 'Really delete %s?' % re_name),
                                    'class': 'removelink',
                                    'title': 'Delete %s runtime environment' % re_name, 
                                    'text': ''}
        runtimeenvironments.append(re_item)

    output_objects.append({'object_type': 'table_pager', 'entry_name': 'runtime envs',
                           'default_entries': default_pager_entries})
    output_objects.append({'object_type': 'runtimeenvironments',
                          'runtimeenvironments': runtimeenvironments})

    if configuration.site_swrepo_url:
        output_objects.append({'object_type': 'sectionheader', 'text': 'Software Packages'})
        output_objects.append({'object_type': 'link',
                               'destination': configuration.site_swrepo_url,
                               'class': 'swrepolink',
                               'title': 'Browse available software packages',
                               'text': 'Open software catalogue for %s' % \
                               configuration.short_title,
                               })

    output_objects.append({'object_type': 'sectionheader', 'text': 'Additional Runtime Environments'})
    output_objects.append({'object_type': 'link',
                           'destination': 'adminre.py',
                           'class': 'addlink',
                           'title': 'Specify a new runtime environment', 
                           'text': 'Create a new runtime environment'})

    return (output_objects, returnvalues.OK)
Beispiel #7
0
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)
Beispiel #8
0
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)
    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_description = accepted['description'][-1].lower() == 'true'

    # 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

    template_path = os.path.join(base_dir, default_mrsl_filename)

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'Submit Job'
    output_objects.append({'object_type': 'header', 'text'
                          : 'Submit Job'})
    default_mrsl = get_default_mrsl(template_path)
    settings_dict = load_settings(client_id, configuration)
    if not settings_dict or not settings_dict.has_key('SUBMITUI'):
        logger.info('Settings dict does not have SUBMITUI key - using default'
                    )
        submit_style = configuration.submitui[0]
    else:
        submit_style = settings_dict['SUBMITUI']

    # We generate all 3 variants of job submission (fields, textarea, files),
    # initially hide them and allow to switch between them using js.

    # could instead extract valid prefixes as in settings.py
    # (means: by "eval" from configuration). We stick to hard-coding.
    submit_options = ['fields_form', 'textarea_form', 'files_form']

    css_helpers = {'css_base': os.path.join(configuration.site_images, 'css'),
                   'skin_base': configuration.site_skin_base}
    title_entry['style'] = themed_styles(configuration,
                                         base=['jquery.fileupload.css',
                                               'jquery.fileupload-ui.css'],
                                         skin=['fileupload-ui.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 is only needed for fancy upload init wrapper -->
<script type="text/javascript" src="/images/js/jquery.form.js"></script>
<script type="text/javascript" src="/images/js/jquery.filemanager.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>
<!-- 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>

<script type="text/javascript" >

    options = %s;

    function setDisplay(this_id, new_d) {
        //console.log("setDisplay with: "+this_id);
        el = document.getElementById(this_id)
        if ( el == undefined || el.style == undefined ) {
            console.log("failed to locate display element: "+this_id);
            return; // avoid js null ref errors
        }
        el.style.display=new_d;
    }

    function switchTo(name) {
        //console.log("switchTo: "+name);
        for (o=0; o < options.length; o++) {
            if (name == options[o]) {
                setDisplay(options[o],"block");
            } else {
                setDisplay(options[o],"none");
            }
        }
    }

    function openFancyUpload() {
        var open_dialog = mig_fancyuploadchunked_init("fancyuploadchunked_dialog");
        var remote_path = ".";
        open_dialog("Upload Files", function() { return false; },
                    remote_path, false);
    }

    $(document).ready( function() {
         //console.log("document ready handler");
         switchTo("%s");
         $("#fancydialog").click(openFancyUpload);
    });

</script>
''' % (submit_options, submit_style + "_form")

    output_objects.append({'object_type': 'text', 'text':
                           'This page is used to submit jobs to the grid.'})

    output_objects.append({'object_type': 'verbatim',
                           'text': '''
There are %s interface styles available that you can choose among:''' % \
                           len(submit_options)})

    links = []
    for opt in submit_options:
        name = opt.split('_', 2)[0] 
        links.append({'object_type': 'link', 
                      'destination': "javascript:switchTo('%s')" % opt,
                      'class': 'submit%slink' % name,
                      'title': 'Switch to %s submit interface' % name,
                      'text' : '%s style' % name,
                      })
    output_objects.append({'object_type': 'multilinkline', 'links': links})

    output_objects.append({'object_type': 'text', 'text': '''
Please note that changes to the job description are *not* automatically
transferred if you switch style.'''}) 

    output_objects.append({'object_type': 'html_form', 'text':
                           '<div id="fields_form" style="display:none;">\n'})
    
    # Fields
    output_objects.append({'object_type': 'sectionheader', 'text'
                          : 'Please fill in your job description in the fields'
                           ' below:'
                          })
    output_objects.append({'object_type': 'text', 'text'
                          : """
Please fill in one or more fields below to define your job before hitting
Submit Job at the bottom of the page.
Empty fields will simply result in the default value being used and each field
is accompanied by a help link providing further details about the field."""})
    output_objects.append({'object_type': 'html_form', 'text'
                          : """
<div class="submitjob">
<form method="post" action="submitfields.py">
"""
                          })
    show_fields = get_job_specs(configuration)
    try:
        parsed_mrsl = dict(parse_lines(default_mrsl))
    except:
        parsed_mrsl = {}

    # Find allowed VGrids and Runtimeenvironments and add them to
    # configuration object for automated choice handling
    
    allowed_vgrids = user_allowed_vgrids(configuration, client_id) + \
                     [any_vgrid]
    allowed_vgrids.sort()
    configuration.vgrids = allowed_vgrids
    (re_status, allowed_run_envs) = list_runtime_environments(configuration)
    if not re_status:
        logger.error('Failed to extract allowed runtime envs: %s' % \
                     allowed_run_envs)
        allowed_run_envs = []
    allowed_run_envs.sort()
    configuration.runtimeenvironments = allowed_run_envs
    user_res = user_allowed_res_exes(configuration, client_id)

    # Allow any exe unit on all allowed resources
        
    allowed_resources = ['%s_*' % res for res in user_res.keys()]
    allowed_resources.sort()
    configuration.resources = allowed_resources
    field_size = 30
    area_cols = 80
    area_rows = 5

    for (field, spec) in show_fields:
        title = spec['Title']
        if show_description:
            description = '%s<br />' % spec['Description']
        else:
            description = ''
        field_type = spec['Type']
        # Use saved value and fall back to default if it is missing
        saved = parsed_mrsl.get('::%s::' % field, None)
        if saved:
            if not spec['Type'].startswith('multiple'):
                default = saved[0]
            else:
                default = saved
        else:
            default = spec['Value']
        # Hide sandbox field if sandboxes are disabled
        if field == 'SANDBOX' and not configuration.site_enable_sandboxes:
            continue
        if 'invisible' == spec['Editor']:
            continue
        if 'custom' == spec['Editor']:
            continue
        output_objects.append({'object_type': 'html_form', 'text'
                                   : """
<b>%s:</b>&nbsp;<a class='infolink' href='docs.py?show=job#%s'>help</a><br />
%s""" % (title, field, description)
                               })
        
        if 'input' == spec['Editor']:
            if field_type.startswith('multiple'):
                output_objects.append({'object_type': 'html_form', 'text'
                                       : """
<textarea name='%s' cols='%d' rows='%d'>%s</textarea><br />
""" % (field, area_cols, area_rows, '\n'.join(default))
                               })
            else:
                output_objects.append({'object_type': 'html_form', 'text'
                                       : """
<input type='text' name='%s' size='%d' value='%s' /><br />
""" % (field, field_size, default)
                               })
        elif 'select' == spec['Editor']:
            choices = available_choices(configuration, client_id,
                                        field, spec)
            res_value = default
            value_select = ''
            if field_type.startswith('multiple'):
                value_select += '<div class="scrollselect">'
                for name in choices:
                    # Blank default value does not make sense here
                    if not str(name):
                        continue
                    selected = ''
                    if str(name) in res_value:
                        selected = 'checked'
                    value_select += '''
                        <input type="checkbox" name="%s" %s value=%s>%s<br />
                        ''' % (field, selected, name, name)
                value_select += '</div>\n'
            else:
                value_select += "<select name='%s'>\n" % field
                for name in choices:
                    selected = ''
                    if str(res_value) == str(name):
                        selected = 'selected'
                    display = "%s" % name
                    if display == '':
                        display = ' '
                    value_select += """<option %s value='%s'>%s</option>\n""" \
                                    % (selected, name, display)
                value_select += """</select><br />\n"""    
            output_objects.append({'object_type': 'html_form', 'text'
                                   : value_select
                                   })
        output_objects.append({'object_type': 'html_form', 'text': "<br />"})

    output_objects.append({'object_type': 'html_form', 'text'
                          : """
<br />
<table class='centertext'>
<tr><td><input type='submit' value='Submit Job' />
<input type='checkbox' name='save_as_default'> Save as default job template
</td></tr>
</table>
<br />
</form>
</div>
"""
                           })
    output_objects.append({'object_type': 'html_form', 
                           'text': '''
</div><!-- fields_form-->
<div id="textarea_form" style="display:none;">
'''})
    
    # Textarea
    output_objects.append({'object_type': 'sectionheader', 'text'
                          : 'Please enter your mRSL job description below:'
                          })
    output_objects.append({'object_type': 'html_form', 'text'
                          : """
<div class='smallcontent'>
Job descriptions can use a wide range of keywords to specify job requirements
and actions.<br />
Each keyword accepts one or more values of a particular type.<br />
The full list of keywords with their default values and format is available in
the on-demand <a href='docs.py?show=job'>mRSL Documentation</a>.
<p>
Actual examples for inspiration:
<a href=/public/cpuinfo.mRSL>CPU Info</a>,
<a href=/public/basic-io.mRSL>Basic I/O</a>,
<a href=/public/notification.mRSL>Job Notification</a>,
<a href=/public/povray.mRSL>Povray</a> and
<a href=/public/vcr.mRSL>VCR</a>
</div>
    """})

    output_objects.append({'object_type': 'html_form', 'text'
                          : """
<!-- 
Please note that textarea.py chokes if no nonempty KEYWORD_X_Y_Z fields 
are supplied: thus we simply send a bogus jobname which does nothing
-->
<form method="post" action="textarea.py">
<table class="submitjob">
<tr><td class="centertext">
<input type=hidden name=jobname_0_0_0 value=" " />
<textarea cols="82" rows="25" name="mrsltextarea_0">
%(default_mrsl)s
</textarea>
</td></tr>
<tr><td class='centertext'>
<input type="submit" value="Submit Job" />
<input type="checkbox" name="save_as_default" >Save as default job template
</td></tr>
</table>
</form>
"""
                           % {'default_mrsl': default_mrsl}})

    output_objects.append({'object_type': 'html_form', 
                           'text': '''
</div><!-- textarea_form-->
<div id="files_form" style="display:none;">
'''})
    # Upload form

    output_objects.append({'object_type': 'sectionheader', 'text'
                          : 'Please upload your job file or packaged job files'
                           ' below:'
                          })
    output_objects.append({'object_type': 'html_form', 'text'
                          : """
<form enctype='multipart/form-data' action='textarea.py' method='post'>
<table class='files'>
<tr class='title'><td class='centertext' colspan=4>
Upload job files
</td></tr>
<tr><td colspan=3>
Upload file to current directory (%(dest_dir)s)
</td><td><br /></td></tr>
<tr><td colspan=2>
Extract package files (.zip, .tar.gz, .tar.bz2)
</td><td colspan=2>
<input type=checkbox name='extract_0' />
</td></tr>
<tr><td colspan=2>
Submit mRSL files (also .mRSL files included in packages)
</td><td colspan=2>
<input type=checkbox name='submitmrsl_0' checked />
</td></tr>
<tr><td>    
File to upload
</td><td class='righttext' colspan=3>
<input name='fileupload_0_0_0' type='file'/>
</td></tr>
<tr><td>
Optional remote filename (extra useful in windows)
</td><td class='righttext' colspan=3>
<input name='default_remotefilename_0' type='hidden' value='%(dest_dir)s'/>
<input name='remotefilename_0' type='text' size='50' value='%(dest_dir)s'/>
<input type='submit' value='Upload' name='sendfile'/>
</td></tr>
</table>
</form>
<table class='files'>
<tr class='title'><td class='centertext'>
Upload other files efficiently (using chunking).
</td></tr>
<tr><td class='centertext'>
<button id='fancydialog'>Open Upload dialog</button>
</td></tr>
</table>
</div><!-- files_form-->

<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'>&nbsp;</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>
    """ % {'dest_dir': '.' + os.sep}})
    
    output_objects.append({'object_type': 'html_form', 
                           'text': '''
<!-- 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>
    '''})
    return (output_objects, status)
Beispiel #9
0
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)

    hosturl = accepted['hosturl'][-1]
    hostidentifier = accepted['hostidentifier'][-1]
    resource_id = '%s.%s' % (hosturl, hostidentifier)
    extra_selects = 3

    # Find allowed VGrids and Runtimeenvironments and add them to
    # configuration object for automated choice handling    

    allowed_vgrids = [''] + res_allowed_vgrids(configuration, resource_id)
    allowed_vgrids.sort()

    configuration.vgrids = allowed_vgrids
    (re_status, allowed_run_envs) = list_runtime_environments(configuration)
    allowed_run_envs.sort()
    area_cols = 80
    area_rows = 5
    
    status = returnvalues.OK

    logger.info('Starting Resource edit GUI.')

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'Resource Editor'
    output_objects.append({'object_type': 'header', 'text': 'Resource Editor'
                          })
    output_objects.append({'object_type': 'sectionheader', 'text'
                          : '%s Resource Editor' % configuration.short_title})
    output_objects.append({'object_type': 'text', 'text'
                           : '''
Please fill in or edit the fields below to fit your %s resource reservation. Most fields
will work with their default values. So if you are still in doubt after reading the help
description, you can likely just leave the field alone.''' % configuration.short_title
                          })

    if hosturl and hostidentifier:
        conf = init_conf(configuration, hosturl, hostidentifier)
        if not conf:
            status = returnvalues.CLIENT_ERROR
            output_objects.append({'object_type': 'error_text', 'text'
                           : '''No such resource! (%s.%s)''' % (hosturl, hostidentifier)})
            return (output_objects, status)
    else:
        conf = empty_resource_config(configuration)

    res_fields = resconfkeywords.get_resource_specs(configuration)
    exe_fields = resconfkeywords.get_exenode_specs(configuration)
    store_fields = resconfkeywords.get_storenode_specs(configuration)

    output_objects.append({'object_type': 'html_form', 'text': """
<form method='post' action='reseditaction.py'>
"""
                           })

    # Resource overall fields

    output_objects.append({'object_type': 'sectionheader', 'text'
                           : "Main Resource Settings"})
    output_objects.append({'object_type': 'text', 'text'
                           : """This section configures general options for the resource."""
                           })

    (title, field) = ('Host FQDN', 'HOSTURL')
    if hosturl:
        try:
            hostip = conf.get('HOSTIP', socket.gethostbyname(hosturl))
        except:
            hostip = '<unknown>'
        output_objects.append({'object_type': 'html_form', 'text'
                               : """<br />
<b>%s:</b>&nbsp;<a class='infolink' href='resedithelp.py#res-%s'>help</a><br />
<input type='hidden' name='%s' value='%s' />
<input type='hidden' name='hostip' value='%s' />
%s
<br />
<br />""" % (title, field, field, conf[field], hostip,
           conf[field])
                               })
    else:
        output_objects.append({'object_type': 'html_form', 'text'
                               : """<br />
<b>%s:</b>&nbsp;<a class='infolink' href='resedithelp.py#res-%s'>help</a><br />
<input type='text' name='%s' size='%d' value='%s' />
<br />
<br />""" % (title, field, field, field_size(conf[field]),
           conf[field])
                               })

    (title, field) = ('Host identifier', 'HOSTIDENTIFIER')
    if hostidentifier:
        output_objects.append({'object_type': 'html_form', 'text'
                               : """<br />
<b>%s:</b>&nbsp;<a class='infolink' href='resedithelp.py#res-%s'>help</a><br />
<input type='hidden' name='%s' value='%s' />
%s
<br />
<br />""" % (title, field, field, conf[field], conf[field])
                               })                               

    (field, title) = 'frontendhome', 'Frontend Home Path'
    output_objects.append({'object_type': 'html_form', 'text'
                           : """<br />
<b>%s:</b>&nbsp;<a class='infolink' href='resedithelp.py#%s'>help</a><br />
<input type='text' name='%s' size='%d' value='%s' />
<br />
<br />""" % (title, field, field,
           field_size(conf[field]), conf[field])
                               })

    for (field, spec) in res_fields:
        title = spec['Title']
        field_type = spec['Type']
        if 'invisible' == spec['Editor']:
            continue
        elif 'input' == spec['Editor']:
            output_objects.append({'object_type': 'html_form', 'text'
                                   : """<br />
<b>%s:</b>&nbsp;<a class='infolink' href='resedithelp.py#res-%s'>help</a><br />
<input type='text' name='%s' size='%d' value='%s' />
<br />
<br />""" % (title, field, field, field_size(conf[field]),
           conf[field])
                                   })
        elif 'select' == spec['Editor']:
            choices = available_choices(configuration, client_id,
                                        resource_id, field, spec)
            res_value = conf[field]
            value_select = ''
            if field_type.startswith('multiple'):
                select_count = len(res_value) + extra_selects
            else:
                select_count = 1
                res_value = [res_value]
            for i in range(select_count):
                value_select += "<select name='%s'>\n" % field
                for name in choices:
                    selected = ''
                    if i < len(res_value) and res_value[i] == name:
                        selected = 'selected'
                    display = "%s" % name
                    if display == '':
                        display = ' '
                    value_select += """<option %s value='%s'>%s</option>\n""" \
                                    % (selected, name, display)
                value_select += """</select><br />\n"""    
            output_objects.append({'object_type': 'html_form', 'text'
                                   : """<br />
<b>%s:</b>&nbsp;<a class='infolink' href='resedithelp.py#res-%s'>help</a><br />
%s
<br />""" % (title, field, value_select)
                                   })

    # Not all resource fields here map directly to keywords/specs input field
    
    (title, field) = ('Runtime Environments', 'RUNTIMEENVIRONMENT')
    re_list = conf[field]
    show = re_list + [('', []) for i in range(extra_selects)]
    re_select = "<input type='hidden' name='runtime_env_fields' value='%s'/>\n" \
                % len(show)
    i = 0
    for active in show:
        re_select += "<select name='runtimeenvironment%d'>\n" % i
        for name in allowed_run_envs + ['']:
            selected = ''
            if active[0] == name:
                selected = 'selected'
            display = "%s" % name
            if display == '':
                display = ' '
            re_select += """<option %s value='%s'>%s</option>\n""" % \
                         (selected, name, display)
        re_select += """</select><br />\n"""
        values = '\n'.join(['%s=%s' % pair for pair in active[1]])
        re_select += "<textarea cols='%d' rows='%d' name='re_values%d'>%s</textarea><br />\n" % \
                     (area_cols, area_rows, i, values)
        i += 1

    output_objects.append({'object_type': 'html_form', 'text'
                               : """<br />
<b>%s:</b>&nbsp;<a class='infolink' href='resedithelp.py#res-%s'>help</a><br />
Please enter any required environment variable settings on the form NAME=VALUE in the box below
each selected runtimeenvironment.<br />
%s
<br />""" % (title, field, re_select)
                           })


    # Execution node fields

    output_objects.append({'object_type': 'sectionheader', 'text'
                           : "Execution nodes"})
    output_objects.append({'object_type': 'text', 'text'
                           : """This section configures execution nodes on the resource."""
                           })
    (field, title) = 'executionnodes', 'Execution Node(s)'
    output_objects.append({'object_type': 'html_form', 'text'
                           : """<br />
<b>%s:</b>&nbsp;<a class='infolink' href='resedithelp.py#exe-%s'>help</a><br />
<input type='text' name='exe-%s' size='%d' value='%s' />
<br />
<br />""" % (title, field, field,
           field_size(conf['all_exes'][field]), conf['all_exes'][field])
                               })

    (field, title) = 'executionhome', 'Execution Home Path'
    output_objects.append({'object_type': 'html_form', 'text'
                           : """<br />
<b>%s:</b>&nbsp;<a class='infolink' href='resedithelp.py#exe-%s'>help</a><br />
<input type='text' name='exe-%s' size='%d' value='%s' />
<br />
<br />""" % (title, field, field,
           field_size(conf['all_exes'][field]), conf['all_exes'][field])
                               })

    for (field, spec) in exe_fields:
        title = spec['Title']
        field_type = spec['Type']
        if 'invisible' == spec['Editor']:
            continue
        elif 'input' == spec['Editor']:
            output_objects.append({'object_type': 'html_form', 'text'
                                   : """<br />
<b>%s:</b>&nbsp;<a class='infolink' href='resedithelp.py#exe-%s'>help</a><br />
<input type='text' name='exe-%s' size='%d' value='%s' />
<br />
<br />""" % (title, field, field,
           field_size(conf['all_exes'][field]), conf['all_exes'][field])
                                   })
        elif 'select' == spec['Editor']:
            choices = available_choices(configuration, client_id,
                                        resource_id, field, spec)
            exe_value = conf['all_exes'][field]
            value_select = ''
            if field_type.startswith('multiple'):
                select_count = len(exe_value) + extra_selects
            else:
                select_count = 1
                exe_value = [exe_value]
            for i in range(select_count):
                value_select += "<select name='exe-%s'>\n" % field
                for name in choices:
                    selected = ''
                    if i < len(exe_value) and exe_value[i] == name:
                        selected = 'selected'
                    display = "%s" % name
                    if display == '':
                        display = ' '
                    value_select += """<option %s value='%s'>%s</option>\n""" \
                                    % (selected, name, display)
                value_select += """</select><br />\n"""    
            output_objects.append({'object_type': 'html_form', 'text'
                                   : """<br />
<b>%s:</b>&nbsp;<a class='infolink' href='resedithelp.py#exe-%s'>help</a><br />
%s
<br />""" % (title, field, value_select)
                                   })
    
    # Storage node fields

    output_objects.append({'object_type': 'sectionheader', 'text'
                           : "Storage nodes"})
    output_objects.append({'object_type': 'text', 'text'
                           : """This section configures storage nodes on the resource."""
                           })
    
    (field, title) = 'storagenodes', 'Storage Node(s)'
    output_objects.append({'object_type': 'html_form', 'text'
                           : """<br />
<b>%s:</b>&nbsp;<a class='infolink' href='resedithelp.py#store-%s'>help</a><br />
<input type='text' name='store-%s' size='%d' value='%s' />
<br />
<br />""" % (title, field, field,
           field_size(conf['all_stores'][field]), conf['all_stores'][field])
                               })

    (field, title) = 'storagehome', 'Storage Home Path'
    output_objects.append({'object_type': 'html_form', 'text'
                           : """<br />
<b>%s:</b>&nbsp;<a class='infolink' href='resedithelp.py#store-%s'>help</a><br />
<input type='text' name='store-%s' size='%d' value='%s' />
<br />
<br />""" % (title, field, field,
           field_size(conf['all_stores'][field]), conf['all_stores'][field])
                               })

    for (field, spec) in store_fields:
        title = spec['Title']
        field_type = spec['Type']
        if 'invisible' == spec['Editor']:
            continue
        elif 'input' == spec['Editor']:
            output_objects.append({'object_type': 'html_form', 'text'
                           : """<br />
<b>%s:</b>&nbsp;<a class='infolink' href='resedithelp.py#store-%s'>help</a><br />
<input type='text' name='store-%s' size='%d' value='%s' />
<br />
<br />""" % (title, field, field,
           field_size(conf['all_stores'][field]), conf['all_stores'][field])
                                   })
        elif 'select' == spec['Editor']:
            choices = available_choices(configuration, client_id,
                                        resource_id, field, spec)
            store_value = conf['all_stores'][field]
            value_select = ''
            if field_type.startswith('multiple'):
                select_count = len(store_value) + extra_selects
            else:
                select_count = 1
                store_value = [store_value]
            for i in range(select_count):
                value_select += "<select name='store-%s'>\n" % field
                for name in choices:
                    selected = ''
                    if i < len(store_value) and store_value[i] == name:
                        selected = 'selected'
                    display = "%s" % name
                    if display == '':
                        display = ' '
                    value_select += """<option %s value='%s'>%s</option>\n""" \
                                    % (selected, name, display)
                value_select += """</select><br />\n"""    
            output_objects.append({'object_type': 'html_form', 'text'
                                   : """<br />
<b>%s:</b>&nbsp;<a class='infolink' href='resedithelp.py#store-%s'>help</a><br />
%s
<br />""" % (title, field, value_select)
                                   })

    output_objects.append({'object_type': 'html_form', 'text': """
<input type='submit' value='Save' />
</form>
"""
                           })

    return (output_objects, status)