Exemplo n.º 1
0
                    # OUTPUTFILES is either just combo path or src dst paths
                    
                    parts = path.split()
                    
                    # Always take last part as destination

                    path_string += 'path=%s;' % parts[-1]

                job_obj['outputfileslink'] = {'object_type': 'link',
                                              'destination': 'ls.py?%s' % \
                                              path_string,
                                              'text': 'View output files'}

            js_name = 'resubmit%s' % hexlify(job_id)
            helper = html_post_helper(js_name, 'resubmit.py',
                                      {'job_id': job_id})
            output_objects.append({'object_type': 'html_form', 'text': helper})
            job_obj['resubmitlink'] = {'object_type': 'link',
                                       'destination':
                                       "javascript: %s();" % js_name,
                                       'text': 'Resubmit job'}

            js_name = 'freeze%s' % hexlify(job_id)
            helper = html_post_helper(js_name, 'jobaction.py',
                                      {'action': 'freeze','job_id': job_id})
            output_objects.append({'object_type': 'html_form', 'text': helper})
            job_obj['freezelink'] = {'object_type': 'link',
                                     'destination':
                                     "javascript: %s();" % js_name,
                                     'text': 'Freeze job in queue'}
            js_name = 'thaw%s' % hexlify(job_id)
Exemplo n.º 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]
    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = "Show freeze"
    (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)

    freeze_id = accepted['freeze_id'][-1]
    flavor = accepted['flavor'][-1]
    checksum_list = [i for i in accepted['checksum'] if i]
    operation = accepted['operation'][-1]

    if not flavor in freeze_flavors.keys():
        output_objects.append({
            'object_type': 'error_text',
            'text': 'Invalid freeze flavor: %s' % flavor
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    title = freeze_flavors[flavor]['showfreeze_title']
    title_entry['text'] = title
    output_objects.append({'object_type': 'header', 'text': title})

    sorted_algos = supported_hash_algos()
    sorted_algos.sort()
    for checksum in checksum_list:
        if not checksum in sorted_algos:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Invalid checksum algo(s): %s' % checksum
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

    if not configuration.site_enable_freeze:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''Freezing archives is disabled on this site.
Please contact the site admins %s if you think it should be enabled.
''' % configuration.admin_email
        })
        return (output_objects, returnvalues.OK)

    if not operation in allowed_operations:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''Operation must be one of %s.''' % ', '.join(allowed_operations)
        })
        return (output_objects, returnvalues.OK)

    # We don't generally know checksum and edit status until AJAX returns
    hide_elems = {'edit': 'hidden', 'update': 'hidden', 'register': 'hidden'}
    for algo in sorted_algos:
        hide_elems['%ssum' % algo] = 'hidden'

    if operation in show_operations:

        # jquery support for tablesorter and confirmation dialog
        # table initially sorted by col. 0 (filename)

        refresh_call = 'ajax_showfreeze("%s", "%s", %s, "%s", "%s", "%s", "%s")' % \
                       (freeze_id, flavor, checksum_list, keyword_updating,
                        keyword_final, configuration.site_freeze_doi_url,
                        configuration.site_freeze_doi_url_field)
        table_spec = {
            'table_id': 'frozenfilestable',
            'sort_order': '[[0,0]]',
            'refresh_call': refresh_call
        }
        (add_import, add_init,
         add_ready) = man_base_js(configuration, [table_spec])
        if operation == "show":
            add_ready += '%s;' % refresh_call

        # Only show requested checksums
        for algo in sorted_algos:
            if algo in checksum_list:
                add_ready += """
        $('.%ssum').show();
""" % checksum
            else:
                add_ready += """
        $('.%ssum').hide();
        """ % algo

        title_entry['script']['advanced'] += add_import
        title_entry['script']['init'] += add_init
        title_entry['script']['ready'] += add_ready
        output_objects.append({
            'object_type': 'html_form',
            'text': man_base_html(configuration)
        })
        output_objects.append({
            'object_type': 'table_pager',
            'entry_name': 'frozen files',
            'default_entries': default_pager_entries,
            'refresh_button': False
        })

        # Helper form for removes

        form_method = 'post'
        csrf_limit = get_csrf_limit(configuration)
        target_op = 'deletefreeze'
        csrf_token = make_csrf_token(configuration, form_method, target_op,
                                     client_id, csrf_limit)
        helper = html_post_helper(
            'delfreeze', '%s.py' % target_op, {
                'freeze_id': '__DYNAMIC__',
                'flavor': '__DYNAMIC__',
                'path': '__DYNAMIC__',
                'target': TARGET_PATH,
                csrf_field: csrf_token
            })
        output_objects.append({'object_type': 'html_form', 'text': helper})

    # NB: the restrictions on freeze_id prevents illegal directory traversal

    if not is_frozen_archive(client_id, freeze_id, configuration):
        logger.error("%s: invalid freeze '%s': %s" %
                     (op_name, client_id, freeze_id))
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            "'%s' is not an existing frozen archive!" % freeze_id
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    if operation in list_operations:
        (load_status,
         freeze_dict) = get_frozen_archive(client_id, freeze_id, configuration,
                                           checksum_list)
        if not load_status:
            logger.error("%s: load failed for '%s': %s" %
                         (op_name, freeze_id, freeze_dict))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Could not read details for "%s"' % freeze_id
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)

        if freeze_dict.get('FLAVOR', 'freeze') != flavor:
            logger.error("%s: flavor mismatch for '%s': %s vs %s" %
                         (op_name, freeze_id, flavor, freeze_dict))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'No such %s archive "%s"' % (flavor, freeze_id)
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

        # Allow edit if not in updating/final state and allow request DOI if
        # finalized and not a backup archive.
        freeze_state = freeze_dict.get('STATE', keyword_final)
        if freeze_state == keyword_updating:
            hide_elems['update'] = ''
        elif freeze_state != keyword_final:
            hide_elems['edit'] = ''
        elif flavor != 'backup' and configuration.site_freeze_doi_url and \
                freeze_dict.get('PUBLISH_URL', ''):
            hide_elems['register'] = ''

        logger.debug("%s: build obj for '%s': %s" %
                     (op_name, freeze_id, brief_freeze(freeze_dict)))
        output_objects.append(
            build_freezeitem_object(configuration, freeze_dict))

    if operation == "show":
        # insert dummy placeholder to build table
        output_objects.append({
            'object_type': 'frozenarchive',
            'id': freeze_id,
            'creator': client_id,
            'flavor': flavor,
            'frozenfiles': [],
            'name': 'loading ...',
            'description': 'loading ...',
            'created': 'loading ...',
            'state': 'loading ...'
        })
    if operation in show_operations:
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            """<p>
Show archive with file checksums - might take quite a while to calculate:
</p>"""
        })
        for algo in sorted_algos:
            output_objects.append({'object_type': 'html_form', 'text': '<p>'})
            output_objects.append({
                'object_type':
                'link',
                'destination':
                "showfreeze.py?freeze_id=%s;flavor=%s;checksum=%s" %
                (freeze_id, flavor, algo),
                'class':
                'infolink iconspace genericbutton',
                'title':
                'View archive with %s checksums' % algo.upper(),
                'text':
                'Show with %s checksums' % algo.upper()
            })
            output_objects.append({'object_type': 'html_form', 'text': '</p>'})

        # We don't know state of archive in this case until AJAX returns
        # so we hide the section and let AJAX show it if relevant
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            """
<div class='updatearchive %(update)s'>
<p class='warn_message'>
Archive is currently in the process of being updated. No further changes can be
applied until running archive operations are completed. 
</p>
</div>
<div class='editarchive %(edit)s'>
<p>
You can continue inspecting and changing your archive until you're satisfied,
then finalize it for actual persistent freezing.
</p>
<p>""" % hide_elems
        })
        output_objects.append({
            'object_type':
            'link',
            'destination':
            "adminfreeze.py?freeze_id=%s;flavor=%s" % (freeze_id, flavor),
            'class':
            'editarchivelink iconspace genericbutton',
            'title':
            'Further modify your pending %s archive' % flavor,
            'text':
            'Edit archive'
        })
        output_objects.append({'object_type': 'html_form', 'text': '</p>'})
        form_method = 'post'
        target_op = 'createfreeze'
        csrf_limit = get_csrf_limit(configuration)
        csrf_token = make_csrf_token(configuration, form_method, target_op,
                                     client_id, csrf_limit)
        helper = html_post_helper(
            'createfreeze', '%s.py' % target_op, {
                'freeze_id': freeze_id,
                'flavor': flavor,
                'freeze_state': keyword_final,
                csrf_field: csrf_token
            })
        output_objects.append({'object_type': 'html_form', 'text': helper})
        output_objects.append({
            'object_type':
            'link',
            'destination':
            "javascript: confirmDialog(%s, '%s');" %
            ('createfreeze', 'Really finalize %s?' % freeze_id),
            'class':
            'finalizearchivelink iconspace genericbutton',
            'title':
            'Finalize %s archive to prevent further changes' % flavor,
            'text':
            'Finalize archive',
        })
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            """
</div>
<div class='registerarchive %(register)s'>
<p>
You can register a <a href='http://www.doi.org/index.html'>Digital Object
Identifier (DOI)</a> for finalized archives. This may be useful in case you
want to reference the contents in a publication.
</p>
""" % hide_elems
        })
        form_method = 'post'
        target_op = 'registerfreeze'
        csrf_limit = get_csrf_limit(configuration)
        csrf_token = make_csrf_token(configuration, form_method, target_op,
                                     client_id, csrf_limit)
        helper = html_post_helper(
            'registerfreeze', configuration.site_freeze_doi_url, {
                'freeze_id': freeze_id,
                'freeze_author': client_id,
                configuration.site_freeze_doi_url_field: '__DYNAMIC__',
                'callback_url': "%s.py" % target_op,
                csrf_field: csrf_token
            })
        output_objects.append({'object_type': 'html_form', 'text': helper})
        output_objects.append({
            'object_type': 'html_form',
            'text': configuration.site_freeze_doi_text
        })
        output_objects.append({
            'object_type':
            'link',
            'destination':
            "javascript: confirmDialog(%s, '%s');" %
            ('registerfreeze', 'Really request DOI for %s?' % freeze_id),
            'class':
            'registerarchivelink iconspace genericbutton',
            'title':
            'Register a DOI for %s archive %s' % (flavor, freeze_id),
            'text':
            'Request archive DOI',
        })
        output_objects.append({
            'object_type': 'html_form',
            'text': """
</div>"""
        })

    output_objects.append({
        'object_type':
        'html_form',
        'text':
        """
    <div class='vertical-spacer'></div>"""
    })

    return (output_objects, returnvalues.OK)
Exemplo n.º 3
0
def build_useritem_object_from_user_dict(configuration, client_id,
                                         visible_user_id, user_home, user_dict,
                                         allow_vgrids):
    """Build a user object based on input user_dict"""

    profile_specs = get_profile_specs()
    user_specs = get_settings_specs()
    user_item = {
        'object_type': 'user_info',
        'user_id': visible_user_id,
        'fields': [],
    }
    if visible_user_id.find('@') != -1:
        show_user_id = pretty_format_user(visible_user_id)
    else:
        show_user_id = visible_user_id
    user_item['fields'].append(('Public user ID', show_user_id))

    public_image = user_dict[CONF].get('PUBLIC_IMAGE', [])
    public_image = [
        rel_path for rel_path in public_image
        if os.path.exists(os.path.join(user_home, rel_path))
    ]

    img_html = '<div class="public_image">'
    if not public_image:
        img_html += '<span class="anonymous-profile-img"></span>'
    for rel_path in public_image:
        img_path = os.path.join(user_home, rel_path)
        img_data = inline_image(configuration, img_path)
        img_html += '<img alt="portrait" class="profile-img" src="%s">' % \
                    img_data
    img_html += '</div>'
    public_profile = user_dict[CONF].get('PUBLIC_PROFILE', [])
    if not public_profile:
        public_profile = ['No public information provided']
    profile_html = ''
    profile_html += '<br/>'.join(public_profile)
    profile_html += ''
    public_html = '<div class="">\n%s\n</div>' % profile_html
    profile_html += '<div class="clear"></div>'
    public_html += '<div class="public_frame">\n%s\n</div>' % img_html
    profile_html += '<div class="clear"></div>'
    user_item['fields'].append(('Public information', public_html))
    vgrids_allow_email = user_dict[CONF].get('VGRIDS_ALLOW_EMAIL', [])
    vgrids_allow_im = user_dict[CONF].get('VGRIDS_ALLOW_IM', [])
    hide_email = user_dict[CONF].get('HIDE_EMAIL_ADDRESS', True)
    hide_im = user_dict[CONF].get('HIDE_IM_ADDRESS', True)
    if hide_email:
        email_vgrids = []
    elif any_vgrid in vgrids_allow_email:
        email_vgrids = allow_vgrids
    else:
        email_vgrids = set(vgrids_allow_email).intersection(allow_vgrids)
    if hide_im:
        im_vgrids = []
    elif any_vgrid in vgrids_allow_im:
        im_vgrids = allow_vgrids
    else:
        im_vgrids = set(vgrids_allow_im).intersection(allow_vgrids)
    show_contexts = ['notify']
    for (key, val) in user_specs:
        proto = key.lower()
        if not val['Context'] in show_contexts:
            continue
        saved = user_dict[CONF].get(key, None)
        if val['Type'] != 'multiplestrings':
            saved = [saved]
        entry = ''
        if not email_vgrids and key == 'EMAIL':
            show_address = ' (email address hidden)'
        elif not im_vgrids and key != 'EMAIL':
            show_address = '(IM address hidden)'
        else:
            show_address = ', '.join(saved)
        if saved:
            form_method = 'post'
            csrf_limit = get_csrf_limit(configuration)
            target_op = 'sendrequestaction'
            csrf_token = make_csrf_token(configuration, form_method, target_op,
                                         client_id, csrf_limit)
            js_name = 'send%s%s' % (proto, hexlify(visible_user_id))
            helper = html_post_helper(
                js_name, '%s.py' % target_op, {
                    'cert_id': visible_user_id,
                    'request_type': 'plain',
                    'protocol': proto,
                    'request_text': '',
                    csrf_field: csrf_token
                })
            entry += helper
            link = 'send%slink' % proto
            link_obj = {
                'object_type':
                'link',
                'destination':
                "javascript: confirmDialog(%s, '%s', '%s');" %
                (js_name, 'Send %s message to %s' %
                 (proto, visible_user_id), 'request_text'),
                'class':
                link,
                'title':
                'Send %s message to %s' % (proto, visible_user_id),
                'text':
                show_address
            }
            entry += "%s " % html_link(link_obj)
        user_item['fields'].append((val['Title'], entry))
    return user_item
Exemplo n.º 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)
    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)

    operation = accepted['operation'][-1]

    if not operation in allowed_operations:
        output_objects.append({
            'object_type':
            'text',
            'text':
            '''Operation must be one of %s.''' % ', '.join(allowed_operations)
        })
        return (output_objects, returnvalues.OK)

    logger.info("%s %s begin for %s" % (op_name, operation, client_id))
    if operation in show_operations:

        # jquery support for tablesorter and confirmation on delete
        # table initially sorted by col. 2 (admin), then 0 (name)

        refresh_call = 'ajax_redb()'
        table_spec = {
            'table_id': 'runtimeenvtable',
            'sort_order': '[[2,1],[0,0]]',
            'refresh_call': refresh_call
        }
        (add_import, add_init,
         add_ready) = man_base_js(configuration, [table_spec])
        if operation == "show":
            add_ready += '%s;' % refresh_call
        title_entry['script']['advanced'] += add_import
        title_entry['script']['init'] += add_init
        title_entry['script']['ready'] += add_ready
        output_objects.append({
            'object_type': 'html_form',
            'text': man_base_html(configuration)
        })

        output_objects.append({
            'object_type': 'header',
            'text': '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 iconspace',
            'title': 'Show information about runtime environment',
            'text': 'Documentation on runtime environments'
        })

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

        # Helper form for removes

        form_method = 'post'
        csrf_limit = get_csrf_limit(configuration)
        target_op = 'deletere'
        csrf_token = make_csrf_token(configuration, form_method, target_op,
                                     client_id, csrf_limit)
        helper = html_post_helper('delre', '%s.py' % target_op, {
            're_name': '__DYNAMIC__',
            csrf_field: csrf_token
        })
        output_objects.append({'object_type': 'html_form', 'text': helper})

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

    runtimeenvironments = []
    if operation in list_operations:
        re_map = get_re_map(configuration)
        provider_map = get_re_provider_map(configuration)

        for (re_name, cache_dict) in re_map.items():
            re_dict = cache_dict[CONF]
            # Set providers explicitly after build_reitem_object to avoid import loop
            re_item = build_reitem_object(configuration, re_dict)
            re_name = re_item['name']
            re_item['providers'] = provider_map.get(re_name, [])
            re_item['resource_count'] = len(re_item['providers'])

            re_item['viewruntimeenvlink'] = {
                'object_type': 'link',
                'destination': "showre.py?re_name=%s" % re_name,
                'class': 'infolink iconspace',
                'title': 'View %s runtime environment' % re_name,
                'text': ''
            }
            if client_id == re_item['creator']:
                re_item['ownerlink'] = {
                    'object_type':
                    'link',
                    'destination':
                    "javascript: confirmDialog(%s, '%s', %s, %s);" %
                    ('delre', 'Really delete %s?' % re_name, 'undefined',
                     "{re_name: '%s'}" % re_name),
                    'class':
                    'removelink iconspace',
                    'title':
                    'Delete %s runtime environment' % re_name,
                    'text':
                    ''
                }
            runtimeenvironments.append(re_item)

    output_objects.append({
        'object_type': 'runtimeenvironments',
        'runtimeenvironments': runtimeenvironments
    })

    if operation in show_operations:
        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 iconspace',
                '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 iconspace',
            'title': 'Specify a new runtime environment',
            'text': 'Create a new runtime environment'
        })

    logger.info("%s %s end for %s" % (op_name, operation, client_id))
    return (output_objects, returnvalues.OK)
Exemplo n.º 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]
    (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)
Exemplo n.º 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'] = 'Frozen Archives'
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
    )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    operation = accepted['operation'][-1]

    if not configuration.site_enable_freeze:
        output_objects.append({
            'object_type':
            'text',
            'text':
            '''Freezing archives is disabled on this site.
Please contact the site admins %s if you think it should be enabled.
''' % configuration.admin_email
        })
        return (output_objects, returnvalues.OK)

    if not operation in allowed_operations:
        output_objects.append({
            'object_type':
            'text',
            'text':
            '''Operation must be one of %s.''' % ', '.join(allowed_operations)
        })
        return (output_objects, returnvalues.OK)

    logger.info("%s %s begin for %s" % (op_name, operation, client_id))
    if operation in show_operations:

        # jquery support for tablesorter and confirmation on delete
        # table initially sorted by col. 5 (State), 3 (Created date), 2 (name)

        if client_id in configuration.site_freeze_admins:
            permanent_flavors = []
        else:
            permanent_flavors = configuration.site_permanent_freeze
        # NOTE: must insert permanent_flavors list as string here
        refresh_call = 'ajax_freezedb(%s, "%s")' % (str(permanent_flavors),
                                                    keyword_final)
        table_spec = {
            'table_id': 'frozenarchivetable',
            'sort_order': '[[5,1],[3,1],[2,0]]',
            'refresh_call': refresh_call
        }
        (add_import, add_init,
         add_ready) = man_base_js(configuration, [table_spec])
        if operation == "show":
            add_ready += '%s;' % refresh_call
        title_entry['script']['advanced'] += add_import
        title_entry['script']['init'] += add_init
        title_entry['script']['ready'] += add_ready
        output_objects.append({
            'object_type': 'html_form',
            'text': man_base_html(configuration)
        })

        output_objects.append({
            'object_type': 'header',
            'text': 'Frozen Archives'
        })

        output_objects.append({
            'object_type':
            'text',
            'text':
            '''Frozen archives are write-once collections of files used e.g.
in relation to conference paper submissions. Please note that local policies
may prevent users from deleting frozen archives without explicit acceptance
from the management.
        '''
        })

        output_objects.append({
            'object_type': 'sectionheader',
            'text': 'Existing frozen archives'
        })

        # Helper form for removes

        form_method = 'post'
        csrf_limit = get_csrf_limit(configuration)
        target_op = 'deletefreeze'
        csrf_token = make_csrf_token(configuration, form_method, target_op,
                                     client_id, csrf_limit)
        helper = html_post_helper(
            'delfreeze', '%s.py' % target_op, {
                'freeze_id': '__DYNAMIC__',
                'flavor': '__DYNAMIC__',
                'target': TARGET_ARCHIVE,
                csrf_field: csrf_token
            })
        output_objects.append({'object_type': 'html_form', 'text': helper})

        output_objects.append({
            'object_type': 'table_pager',
            'entry_name': 'frozen archives',
            'default_entries': default_pager_entries
        })

    frozenarchives = []
    if operation in list_operations:
        # NOTE: we do NOT enforce creator match here as edituser can't update
        #       without breaking any published archives
        (list_status, ret) = list_frozen_archives(configuration,
                                                  client_id,
                                                  strict_owner=False)
        if not list_status:
            logger.error("%s: failed for '%s': %s" % (op_name, client_id, ret))
            output_objects.append({'object_type': 'error_text', 'text': ret})
            return (output_objects, returnvalues.SYSTEM_ERROR)

        logger.debug("%s %s: building list of archives" % (op_name, operation))
        for freeze_id in ret:
            # TODO: add file count to meta and switch here
            # (load_status, freeze_dict) = get_frozen_meta(client_id, freeze_id,
            #                                             configuration)
            (load_status, freeze_dict) = get_frozen_archive(client_id,
                                                            freeze_id,
                                                            configuration,
                                                            checksum_list=[])
            if not load_status:
                logger.error("%s: load failed for '%s': %s" %
                             (op_name, freeze_id, freeze_dict))
                output_objects.append({
                    'object_type':
                    'error_text',
                    'text':
                    'Could not read details for "%s"' % freeze_id
                })
                return (output_objects, returnvalues.SYSTEM_ERROR)
            freeze_item = build_freezeitem_object(configuration,
                                                  freeze_dict,
                                                  summary=True)
            freeze_id = freeze_item['id']
            flavor = freeze_item.get('flavor', 'freeze')

            # Users may view all their archives
            freeze_item['viewfreezelink'] = {
                'object_type':
                'link',
                'destination':
                "showfreeze.py?freeze_id=%s;flavor=%s" % (freeze_id, flavor),
                'class':
                'infolink iconspace',
                'title':
                'View frozen archive %s' % freeze_id,
                'text':
                ''
            }
            # Users may edit pending archives
            if freeze_item['state'] != keyword_final:
                freeze_item['editfreezelink'] = {
                    'object_type': 'link',
                    'destination': "adminfreeze.py?freeze_id=%s" % freeze_id,
                    'class': 'adminlink iconspace',
                    'title': 'Edit archive %s' % freeze_id,
                    'text': ''
                }
            # Users may delete pending or non permanent archives.
            # Freeze admins may delete all their own archives.
            if freeze_item['state'] != keyword_final or \
                    flavor not in configuration.site_permanent_freeze or \
                    client_id in configuration.site_freeze_admins:
                freeze_item['delfreezelink'] = {
                    'object_type':
                    'link',
                    'destination':
                    "javascript: confirmDialog(%s, '%s', %s, %s);" %
                    ('delfreeze', 'Really remove %s?' % freeze_id, 'undefined',
                     "{freeze_id: '%s', flavor: '%s'}" % (freeze_id, flavor)),
                    'class':
                    'removelink iconspace',
                    'title':
                    'Remove %s' % freeze_id,
                    'text':
                    ''
                }

            frozenarchives.append(freeze_item)
        logger.debug("%s %s: inserting list of %d archives" %
                     (op_name, operation, len(frozenarchives)))

    output_objects.append({
        'object_type': 'frozenarchives',
        'frozenarchives': frozenarchives
    })

    if operation in show_operations:
        output_objects.append({
            'object_type': 'sectionheader',
            'text': 'Additional Frozen Archives'
        })
        output_objects.append({
            'object_type':
            'text',
            'text':
            """
You can create frozen snapshots/archives of particular subsets of your data in
order to make sure a verbatim copy is preserved. The freeze archive method
includes support for persistent publishing, so that you can e.g. reference your
data in publications. Backup archives can be used as a basic backup mechanism,
so that you can manually recover from any erroneous file removals."""
        })

        output_objects.append({
            'object_type':
            'html_form',
            'text':
            """<p>
Choose one of the archive methods below to make a manual archive:
</p>
<p>"""
        })
        output_objects.append({
            'object_type': 'link',
            'destination': 'adminfreeze.py?flavor=freeze',
            'class': 'addlink iconspace',
            'title': 'Make a new freeze archive of e.g. '
            'research data to be published',
            'text': 'Create a new freeze archive'
        })
        output_objects.append({'object_type': 'html_form', 'text': '</p><p>'})
        output_objects.append({
            'object_type':
            'link',
            'destination':
            'adminfreeze.py?flavor=backup',
            'class':
            'addlink iconspace',
            'title':
            'Make a new backup archive of %s data' % configuration.short_title,
            'text':
            'Create a new backup archive'
        })
        output_objects.append({
            'object_type': 'html_form',
            'text': "<br/><br/></p>"
        })

        if configuration.site_enable_duplicati:
            output_objects.append({
                'object_type':
                'text',
                'text':
                '''
Alternatively you can use Duplicati for traditional incremental backup/restore
with optional encryption of all your backup contents.'''
            })
            output_objects.append({
                'object_type':
                'html_form',
                'text':
                """
<p>For further details please refer to the """
            })
            output_objects.append({
                'object_type': 'link',
                'destination': 'setup.py?topic=duplicati',
                'class': '',
                'title': 'Open Duplicati settings',
                'text': 'Duplicati Settings'
            })
            output_objects.append({
                'object_type':
                'html_form',
                'text':
                """ and the %s documentation.<br/><br/></p>""" %
                configuration.short_title
            })

        if configuration.site_enable_seafile:
            output_objects.append({
                'object_type':
                'text',
                'text':
                '''
We recommend our Seafile sync solution for any small or medium sized data sets,
for which you want automatic file versioning and easy roll-back support.'''
            })
            output_objects.append({
                'object_type':
                'html_form',
                'text':
                """
<p>For further details please refer to the """
            })
            output_objects.append({
                'object_type': 'link',
                'destination': 'setup.py?topic=seafile',
                'class': '',
                'title': 'Open Seafile settings',
                'text': 'Seafile Settings'
            })
            output_objects.append({
                'object_type':
                'html_form',
                'text':
                """ and the %s documentation.</p>""" %
                configuration.short_title
            })
    logger.info("%s %s end for %s" % (op_name, operation, client_id))
    return (output_objects, returnvalues.OK)
Exemplo n.º 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)
    client_dir = client_id_dir(client_id)
    defaults = signature()[1]
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
    )

    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    logger.debug("User: %s executing %s", client_id, op_name)
    if not configuration.site_enable_cloud:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'The cloud service is not enabled on the system'
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)

    status = returnvalues.OK
    user_map = get_full_user_map(configuration)
    user_dict = user_map.get(client_id, None)
    # Optional limitation of cloud access permission
    if not user_dict or not cloud_access_allowed(configuration, user_dict):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            "You don't have permission to access the cloud facilities on "
            "this site"
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    services = configuration.cloud_services

    # Show cloud services menu
    (add_import, add_init, add_ready) = man_base_js(configuration, [])

    add_init += '''
    function get_instance_id() {
        console.log("in get_instance_id");
        console.log("found val: "+$("#select-instance-id").val());
        return $("#select-instance-id").val();
    }
    function get_instance_label() {
        console.log("in get_instance_label");
        console.log("found val: "+$("#select-instance-id > option:selected").text());
        return $("#select-instance-id > option:selected").text();
    }
    '''
    add_ready += '''
        /* NOTE: requires managers CSS fix for proper tab bar height */
        $(".cloud-tabs").tabs();
    '''

    title_entry = find_entry(output_objects, 'title')
    title_entry['script']['advanced'] += add_import
    title_entry['script']['init'] += add_init
    title_entry['script']['ready'] += add_ready
    output_objects.append({
        'object_type': 'html_form',
        'text': man_base_html(configuration)
    })

    output_objects.append({
        'object_type': 'header',
        'text': 'Select a Cloud Service'
    })

    fill_helpers = {
        'cloud_tabs':
        ''.join([
            '<li><a href="#%s-tab">%s</a></li>' %
            (service['service_name'], service['service_title'])
            for service in services
        ])
    }

    output_objects.append({
        'object_type':
        'html_form',
        'text':
        '''
    <div id="wrap-tabs" class="cloud-tabs">
    <ul>
    %(cloud_tabs)s
    </ul>
    ''' % fill_helpers
    })

    form_method = 'post'
    csrf_limit = get_csrf_limit(configuration)
    fill_helpers = {
        'site': configuration.short_title,
        'form_method': form_method,
        'csrf_field': csrf_field,
        'csrf_limit': csrf_limit
    }
    target_op = 'reqcloudservice'
    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})

    action_list = [
        ('start', 'Start'),
        ('stop', 'Stop'),
        ('softrestart', 'Soft boot'),
        ('hardrestart', 'Hard boot'),
        ('status', 'Status'),
        # NOTE: expose console on status page
        #('webaccess', 'Console'),
        ('updatekeys', 'Set keys on'),
        ('create', 'Create'),
        ('delete', 'Delete')
    ]
    # Delete instance form helper shared for all cloud services
    helper = html_post_helper(
        "%s" % target_op, '%s.py' % target_op, {
            'instance_id': '__DYNAMIC__',
            'service': '__DYNAMIC__',
            'action': 'delete',
            csrf_field: csrf_token
        })
    output_objects.append({'object_type': 'html_form', 'text': helper})

    for service in services:
        logger.debug("service: %s" % service)
        cloud_id = service['service_name']
        cloud_title = service['service_title']
        rules_of_conduct = service['service_rules_of_conduct']
        cloud_flavor = service.get("service_provider_flavor", "openstack")

        output_objects.append({
            'object_type':
            'html_form',
            'text':
            '''
        <div id="%s-tab">
        ''' % cloud_id
        })

        if service['service_desc']:
            output_objects.append({
                'object_type': 'sectionheader',
                'text': 'Service Description'
            })
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            '''
        <div class="cloud-description">
        <span>%s</span>
        </div>
        ''' % service['service_desc']
        })
        output_objects.append({
            'object_type': 'html_form',
            'text': '''
        <br/>
        '''
        })

        if not check_cloud_available(configuration, client_id, cloud_id,
                                     cloud_flavor):
            logger.error("Failed to connect to cloud: %s" % cloud_id)
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 'The %s cloud service is currently unavailable' % \
                 cloud_title})
            output_objects.append({
                'object_type': 'html_form',
                'text': '''
        </div>
            '''
            })
            status = returnvalues.SYSTEM_ERROR
            continue

        # Lookup user-specific allowed images (colon-separated image names)
        allowed_images = allowed_cloud_images(configuration, client_id,
                                              cloud_id, cloud_flavor)
        if not allowed_images:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                "No valid instance images for %s" % cloud_title
            })
            output_objects.append({
                'object_type': 'html_form',
                'text': '''
        </div>
            '''
            })
            continue

        fill_helpers.update({
            'cloud_id': cloud_id,
            'cloud_title': cloud_title,
            'target_op': target_op,
            'rules_of_conduct': rules_of_conduct
        })

        delete_html = ""
        # Manage existing instances
        saved_instances = cloud_load_instance(configuration, client_id,
                                              cloud_id, keyword_all)

        saved_fields = ['INSTANCE_IMAGE']
        instance_fields = ['public_fqdn', 'status']
        status_map = status_all_cloud_instances(configuration, client_id,
                                                cloud_id, cloud_flavor,
                                                saved_instances.keys(),
                                                instance_fields)

        # TODO: halfwidth styling does not really work on select elements
        delete_html += """
    <div class='cloud-instance-delete fillwidth'>
        <h3>Permanently delete a %(cloud_title)s cloud instance</h3>
        <form class='delete-cloud-instance' target='#'>
            <p class='cloud-instance-input fillwidth'>
            <label class='fieldlabel halfwidth'>Instance</label>
            <span class='halfwidth'>
            <select id='select-instance-id'
            class='styled-select html-select halfwidth padspace'
            name='instance_id'>
        """ % fill_helpers

        output_objects.append({
            'object_type':
            'html_form',
            'text':
            """
        <div class='cloud-management fillwidth'>
        <h3>Manage %(cloud_title)s instances</h3>
        <br/>
        <div class='cloud-instance-grid'>
        <div class='cloud-instance-grid-left'>
        <label class='fieldlabel fieldheader'>Name</label>
        </div>
        <div class='cloud-instance-grid-middle'>
        <label class='fieldlabel fieldheader'>Instance Details</label>
        </div>
        <div class='cloud-instance-grid-right'>
        <label class='fieldlabel fieldheader'>Actions</label>
        </div>
            """ % fill_helpers
        })
        for (instance_id, instance_dict) in saved_instances.items():
            instance_label = instance_dict.get('INSTANCE_LABEL', instance_id)
            logger.debug("Management entries for %s %s cloud instance %s" %
                         (client_id, cloud_id, instance_id))
            instance_html = """
        <div class='cloud-instance-grid-left'>
        <label class='fieldlabel'>%s</label>
        </div>
        <div class='cloud-instance-grid-middle'>
            """ % instance_label
            for field in saved_fields:
                field_val = saved_instances[instance_id].get(field, "-")
                if field == 'INSTANCE_IMAGE':
                    for (img_name, _, img_alias) in allowed_images:
                        if img_name == field_val:
                            field_val = img_alias
                instance_html += """
            <span class='fieldstatus entry leftpad'>%s</span>
            """ % field_val
            for field in instance_fields:
                field_val = status_map[instance_id].get(field, "-")
                instance_html += """
            <span class='fieldstatus entry leftpad'>%s</span>
            """ % field_val
            instance_html += """
        </div>
        <div class='cloud-instance-grid-right'>
            """
            output_objects.append({
                'object_type': 'html_form',
                'text': instance_html
            })
            for (action, title) in action_list:
                if action in cloud_edit_actions:
                    continue
                query = 'action=%s;service=%s;instance_id=%s' % \
                        (action, cloud_id, instance_id)
                url = 'reqcloudservice.py?%s' % query
                #output_service = {
                #    'object_type': 'service',
                #    'name': "%s" % title,
                #    'targetlink': url
                #}
                #output_objects.append(output_service)
                output_objects.append({
                    'object_type':
                    'link',
                    'destination':
                    url,
                    'text':
                    title,
                    'class':
                    'ui-button',
                    'title':
                    '%s %s' % (title, instance_label)
                })

            output_objects.append({
                'object_type':
                'html_form',
                'text':
                """
        </div>        
            """
            })
            delete_html += """<option value='%s'>%s</option>
            """ % (instance_id, instance_label)

        output_objects.append({
            'object_type':
            'html_form',
            'text':
            """
        </div>
        </div>
        """
        })

        delete_html += """
            </select>
            </span>
            </p>
            <p class='fillwidth'>
            <input type='submit' value='Delete Instance' onClick='javascript:confirmDialog(%(target_op)s, \"Really permanently delete your %(cloud_title)s \"+get_instance_label()+\" instance including all local data?\", undefined, {instance_id: get_instance_id(), service: \"%(cloud_id)s\"}); return false;' />
            </p>
        </form>
    </div>
        """ % fill_helpers

        # Create new instance
        create_html = """
    <div class='cloud-instance-create fillwidth'>
        <h3>Create a new %(cloud_title)s cloud instance</h3>
        <form class='create_cloud_instance' method='%(form_method)s' action='%(target_op)s.py'>
            <input type='hidden' name='%(csrf_field)s' value='%(csrf_token)s' />
            <input type='hidden' name='service' value='%(cloud_id)s' />
            <input type='hidden' name='action' value='create' />
            <p class='cloud-instance-input fillwidth'>
            <label class='fieldlabel halfwidth'>Label</label>
            <span class='halfwidth'>
            <input class='halfwidth padspace' type='text' name='instance_label' value='' />
            </span>
            </p>
            <p class='cloud-instance-input fillwidth'>
            <label class='fieldlabel halfwidth'>Image</label>
            <span class='halfwidth'>
            <select class='styled-select html-select halfwidth padspace' name='instance_image'>
            """
        for (image_name, _, image_alias) in allowed_images:
            create_html += """<option value='%s'>%s</option>
            """ % (image_name, image_alias)
        create_html += """
            </select>
            </span>
            </p>
            <p class='cloud-instance-input fillwidth'>
            <label class='fieldlabel halfwidth'>
            Accept <a href='%(rules_of_conduct)s'>Cloud Rules of Conduct</a>
            </label>
            <span class='halfwidth'>
            <label class='switch'>
            <input type='checkbox' mandatory name='accept_terms'>
            <span class='slider round'></span></label>
            </span>
            </p>
            <p class='fillwidth'>
            <input type='submit' value='Create Instance' />
            </p>
        </form>
    </div>    
        """
        output_objects.append({
            'object_type': 'html_form',
            'text': create_html % fill_helpers
        })

        if saved_instances:
            output_objects.append({
                'object_type': 'html_form',
                'text': delete_html % fill_helpers
            })

        output_objects.append({
            'object_type': 'html_form',
            'text': '''
        </div>
            '''
        })

    output_objects.append({
        'object_type': 'html_form',
        'text': '''
    </div>
    '''
    })

    return (output_objects, status)
Exemplo n.º 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)
    output_objects.append({'object_type': 'header', 'text':
                           'Virtual Machines'})
    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)

    machine_name = accepted['machine_name'][-1].strip()
    memory = int(accepted['memory'][-1])
    disk = int(accepted['disk'][-1])
    vgrid = [name.strip() for name in accepted['vgrid']]
    architecture = accepted['architecture'][-1].strip()
    cpu_count = int(accepted['cpu_count'][-1])
    cpu_time = int(accepted['cpu_time'][-1])
    op_sys = accepted['os'][-1].strip()
    flavor = accepted['flavor'][-1].strip()
    hypervisor_re = accepted['hypervisor_re'][-1].strip()
    sys_re = accepted['sys_re'][-1].strip()
    action = accepted['action'][-1].strip()

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'Virtual Machines'

    # jquery support for tablesorter and confirmation on "leave":

    css_helpers = {'css_base': os.path.join(configuration.site_images, 'css'),
                   'skin_base': configuration.site_skin_base}
    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" >

$(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"); }
                }
              });

          $(".vm-tabs").tabs();
     }
);
</script>
'''

    if not configuration.site_enable_vmachines:
        output_objects.append({'object_type': 'text', 'text':
                               '''Virtual machines are disabled on this site.
Please contact the Grid admins %s if you think they should be enabled.
''' % configuration.admin_email})
        return (output_objects, returnvalues.OK)

    machine_req = {'memory': memory, 'disk': disk, 'cpu_count': cpu_count,
                   'cpu_time': cpu_time, 'architecture': architecture,
                   'vgrid': vgrid, 'os': op_sys, 'flavor': flavor,
                   'hypervisor_re': hypervisor_re, 'sys_re': sys_re}
    
    menu_items = ['vmrequest']

    # Html fragments

    submenu = render_menu(configuration, menu_class='navsubmenu',
                          base_menu=[], user_menu=menu_items)

    welcome_text = 'Welcome to your %s virtual machine management!' % \
                   configuration.short_title
    desc_text = '''On this page you can:
<ul>
    <li>Request Virtual Machines, by clicking on the button above</li>
    <li>See your virtual machines in the list below.</li>
    <li>Start, and connect to your Virtual Machine by clicking on it.</li>
    <li>Edit or delete your Virtual Machine from the Advanced tab.</li>
</ul>
'''

    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': 'html_form', 'text': submenu})
    output_objects.append({'object_type': 'html_form', 'text'
                          : '<p>&nbsp;</p>'})
    output_objects.append({'object_type': 'sectionheader', 'text'
                          : welcome_text})
    output_objects.append({'object_type': 'html_form', 'text'
                          : desc_text})


    user_vms = vms.vms_list(client_id, configuration)
    if action == 'create':
        if not configuration.site_enable_vmachines:
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 "Virtual machines are disabled on this server"})
            status = returnvalues.CLIENT_ERROR
            return (output_objects, status)
        if not machine_name:
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 "requested build without machine name"})
            status = returnvalues.CLIENT_ERROR
            return (output_objects, status)            
        elif machine_name in [vm["name"] for vm in user_vms]:
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 "requested machine name '%s' already exists!" % machine_name})
            status = returnvalues.CLIENT_ERROR
            return (output_objects, status)
        elif not flavor in vms.available_flavor_list(configuration):
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 "requested pre-built flavor not available: %s" % flavor})
            status = returnvalues.CLIENT_ERROR
            return (output_objects, status)
        elif not hypervisor_re in \
                 vms.available_hypervisor_re_list(configuration):
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 "requested hypervisor runtime env not available: %s" % \
                 hypervisor_re})
        elif not sys_re in vms.available_sys_re_list(configuration):
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 "requested system pack runtime env not available: %s" % \
                 sys_re})
            status = returnvalues.CLIENT_ERROR
            return (output_objects, status)

        # TODO: support custom build of machine using shared/vmbuilder.py

        # request for existing pre-built machine

        vms.create_vm(client_id, configuration, machine_name, machine_req)

    (action_status, action_msg, job_id) = (True, '', None)
    if action in ['start', 'stop', 'edit', 'delete']:
        if not configuration.site_enable_vmachines:
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 "Virtual machines are disabled on this server"})
            status = returnvalues.CLIENT_ERROR
            return (output_objects, status)
    if action == 'start':
        machine = {}
        for entry in user_vms:
            if machine_name == entry['name']:
                for name in machine_req.keys():
                    if isinstance(entry[name], basestring) and \
                                  entry[name].isdigit():
                        machine[name] = int(entry[name])
                    else:
                        machine[name] = entry[name]
                break
        (action_status, action_msg, job_id) = \
                        vms.enqueue_vm(client_id, configuration, machine_name,
                                       machine)
    elif action == 'edit':
        if not machine_name in [vm['name'] for vm in user_vms]:
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 "No such virtual machine: %s" % machine_name})
            status = returnvalues.CLIENT_ERROR
            return (output_objects, status)
        (action_status, action_msg) = \
                        vms.edit_vm(client_id, configuration, machine_name,
                                    machine_req)
    elif action == 'delete':
        if not machine_name in [vm['name'] for vm in user_vms]:
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 "No such virtual machine: %s" % machine_name})
            status = returnvalues.CLIENT_ERROR
            return (output_objects, status)
        (action_status, action_msg) = \
                        vms.delete_vm(client_id, configuration, machine_name)
    elif action == 'stop':
        
        # TODO: manage stop - use live I/O to create vmname.stop in job dir

        pass

    if not action_status:
        output_objects.append({'object_type': 'error_text', 'text':
                               action_msg})
    
    # List the machines here

    output_objects.append({'object_type': 'sectionheader', 'text'
                          : 'Your machines:'})

    # Grab the vms available for the user

    machines = vms.vms_list(client_id, configuration)

    # Visual representation mapping of the machine state

    machine_states = {
        'EXECUTING': 'vm_running.jpg',
        'CANCELED': 'vm_off.jpg',
        'FAILED': 'vm_off.jpg',
        'FINISHED': 'vm_off.jpg',
        'UNKNOWN': 'vm_off.jpg',
        'QUEUED': 'vm_booting.jpg',
        'PARSE': 'vm_booting.jpg',
        }

    # Empirical upper bound on boot time in seconds used to decide between
    # desktop init and ready states

    boot_secs = 130

    # CANCELED/FAILED/FINISHED -> Powered Off
    # QUEUED -> Booting

    if len(machines) > 0:

        # Create a pretty list with start/edit/stop/connect links

        pretty_machines = \
            '<table style="border: 0; background: none;"><tr>'
        side_by_side = 3  # How many machines should be shown in a row?

        col = 0
        for machine in machines:

            # Machines on a row

            if col % side_by_side == 0:
                pretty_machines += '</tr><tr>'
            col += 1

            # Html format machine specifications in a fieldset

            password = '******'
            exec_time = 0
            if machine['job_id'] != 'UNKNOWN' and \
                   machine['status'] == 'EXECUTING':

                # TODO: improve on this time selection...
                # ... in distributed there is no global clock!

                exec_time = time.time() - 3600 \
                            - time.mktime(machine['execution_time'])
                password = vms.vnc_jobid(machine['job_id'])

            machine_specs = {}
            machine_specs.update(machine)
            machine_specs['password'] = password
            show_specs = """<fieldset>
<legend>VM Specs:</legend><ul class="no-bullets">
<li><input type="text" readonly value="%(os)s"> base system</li>
<li><input type="text" readonly value="%(flavor)s"> software flavor</li>
<li><input type="text" readonly value="%(memory)s"> MB memory</li>
<li><input type="text" readonly value="%(disk)s"> GB disk</li>
<li><input type="text" readonly value="%(cpu_count)s"> CPU's</li>
<li><input type="text" readonly value="%(vm_arch)s"> architecture</li>
"""
            if password != 'UNKNOWN':
                show_specs += """            
<li><input type="text" readonly value="%(password)s"> as VNC password</li>
"""
            show_specs += """            
</form></ul></fieldset>"""
            edit_specs = """<fieldset>
<legend>Edit VM Specs:</legend><ul class="no-bullets">
<form method="post" action="vmachines.py">
<input type="hidden" name="action" value="edit">
<input type="hidden" name="machine_name" value="%(name)s">
<input type="hidden" name="output_format" value="html">

<li><input type="text" readonly name="os" value="%(os)s"> base system</li>
<li><input type="text" readonly name="flavor" value="%(flavor)s"> software flavor</li>
<li><input type="text" readonly name="hypervisor_re" value="%(hypervisor_re)s"> hypervisor runtime env</li>
<li><input type="text" readonly name="sys_re" value="%(sys_re)s"> image pack runtime env</li>
<li><input type="text" name="memory" value="%(memory)s"> MB memory</li>
<li><input type="text" name="disk" value="%(disk)s"> GB disk</li>
<li><input type="text" name="cpu_count" value="%(cpu_count)s"> CPU's</li>
<li><select name="architecture">
"""
            for arch in [''] + configuration.architectures:
                select = ''
                if arch == machine_specs['architecture']:
                    select = 'selected'
                edit_specs += "<option %s value='%s'>%s</option>" % (select, arch,
                                                                arch)
            edit_specs += """</select> resource architecture
<li><input type="text" name="cpu_time" value="%(cpu_time)s"> s time slot</li>
<li><select name="vgrid" multiple>"""
            for vgrid_name in [any_vgrid] + \
                    user_allowed_vgrids(configuration, client_id):
                select = ''
                if vgrid_name in machine_specs['vgrid']:
                    select = 'selected'
                edit_specs += "<option %s>%s</option>" % (select, vgrid_name)
            edit_specs += """</select> %s(s)</li>""" % \
                          configuration.site_vgrid_label
            if password != 'UNKNOWN':
                edit_specs += """
<li><input type="text" readonly value="%(password)s"> as VNC password</li>
"""
            edit_specs += """
<input class="styled_button" type="submit" value="Save Changes">
</form>"""
            js_name = 'deletevm%s' % hexlify("%(name)s" % machine_specs)
            helper = html_post_helper(js_name, 'vmachines.py',
                                      {'machine_name': machine_specs['name'],
                                       'action': 'delete'})
            edit_specs += helper
            edit_specs += """<input class="styled_button" type="submit"
value="Delete Machine" onClick="javascript: confirmDialog(%s, '%s');" >
""" % (js_name, "Really permanently delete %(name)s VM?" % machine_specs)
            edit_specs += """</ul></fieldset>"""
            if machine['status'] == 'EXECUTING' and exec_time > boot_secs:
                machine_image = '<img src="/images/vms/' \
                    + machine_states[machine['status']] + '">'
            elif machine['status'] == 'EXECUTING' and exec_time < boot_secs:
                machine_image = \
                    '<img src="/images/vms/vm_desktop_loading.jpg' \
                    + '">'
            else:
                machine_image = '<img src="/images/vms/' \
                    + machine_states[machine['status']] + '">'
            machine_link = vms.machine_link(machine_image,
                    machine['job_id'], machine['name'], machine['uuid'
                    ], machine['status'], machine_req)

            # Smack all the html together

            fill_dict = {}
            fill_dict.update(machine)
            fill_dict['link'] = machine_link
            fill_dict['show_specs'] = show_specs % machine_specs
            fill_dict['edit_specs'] = edit_specs % machine_specs
            pretty_machines += '''
<td style="vertical-align: top;">
<fieldset><legend>%(name)s</legend>
<div id="%(name)s-tabs" class="vm-tabs">
<ul>
<li><a href="#%(name)s-overview">Overview</a></li>
<li><a href="#%(name)s-edit">Advanced</a></li>
</ul>
<div id="%(name)s-overview">
<p>%(link)s</p>
%(show_specs)s
</div>
<div id="%(name)s-edit">
%(edit_specs)s
</div>
</div>
</fieldset>
</td>''' % fill_dict

        pretty_machines += '</tr></table>'

        output_objects.append({'object_type': 'html_form', 'text'
                              : pretty_machines})
    else:
        output_objects.append(
            {'object_type': 'text', 'text'
             : "You don't have any virtual machines! "
             "Click 'Request Virtual Machine' to become a proud owner :)"
             })

    return (output_objects, status)
Exemplo n.º 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]
    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)
Exemplo n.º 10
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)

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'Frozen Archives'

    # 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. 0 (ID)
          var sortOrder = [[0,1]];

          // use image path for sorting if there is any inside
          var imgTitle = function(contents) {
              var key = $(contents).find("a").attr("class");
              if (key == null) {
                  key = $(contents).html();
              }
              return key;
          }

          $("#frozenarchivetable").tablesorter({widgets: ["zebra", "saveSort"],
                                        sortList:sortOrder,
                                        textExtraction: imgTitle
                                        })
                               .tablesorterPager({ container: $("#pager"),
                                        size: %s
                                        });
     }
);
</script>
''' % default_pager_entries

    output_objects.append({'object_type': 'header', 'text'
                          : 'Frozen Archives'})
    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>
'''                       })

    if not configuration.site_enable_freeze:
        output_objects.append({'object_type': 'text', 'text':
                               '''Freezing archives is disabled on this site.
Please contact the Grid admins %s if you think it should be enabled.
''' % configuration.admin_email})
        return (output_objects, returnvalues.OK)

    output_objects.append(
        {'object_type': 'text', 'text' :
         '''Frozen archives are write-once collections of files used e.g. in
 relation to conference paper submissions. Please note that local policies may
 prevent users from deleting frozen archives without explicit acceptance from
 the management.
         '''})

    output_objects.append({'object_type': 'sectionheader', 'text'
                          : 'Existing frozen archives'})

    (status, ret) = list_frozen_archives(configuration, client_id)
    if not status:
        logger.error("%s: failed for '%s': %s" % (op_name,
                                                  client_id, ret))
        output_objects.append({'object_type': 'error_text', 'text'
                              : ret})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    frozenarchives = []
    for freeze_id in ret:
        (load_status, freeze_dict) = get_frozen_archive(freeze_id,
                                                        configuration)
        if not load_status:
            logger.error("%s: load failed for '%s': %s" % \
                         (op_name, freeze_id, freeze_dict))
            output_objects.append({'object_type': 'error_text', 'text'
                                   : 'Could not read details for "%s"' % \
                                   freeze_id})
            return (output_objects, returnvalues.SYSTEM_ERROR)
        freeze_item = build_freezeitem_object(configuration, freeze_dict)
        freeze_id = freeze_item['id']
        flavor = freeze_item.get('flavor', 'freeze')
        
        freeze_item['viewfreezelink'] = {
            'object_type': 'link',
            'destination': "showfreeze.py?freeze_id=%s;flavor=%s" % \
            (freeze_id, flavor),
            'class': 'infolink', 
            'title': 'View frozen archive %s' % freeze_id, 
            'text': ''}
        if client_id == freeze_item['creator']:
            js_name = 'delete%s' % hexlify(freeze_id)
            helper = html_post_helper(js_name, 'deletefreeze.py',
                                      {'freeze_id': freeze_id,
                                       'flavor': flavor})
            output_objects.append({'object_type': 'html_form', 'text': helper})
            freeze_item['delfreezelink'] = {
                'object_type': 'link', 'destination':
                "javascript: confirmDialog(%s, '%s');" % \
                (js_name, 'Really remove %s?' % freeze_id),
                'class': 'removelink', 'title': 'Remove %s' % \
                freeze_id, 'text': ''}
        frozenarchives.append(freeze_item)

    output_objects.append({'object_type': 'table_pager', 'entry_name':
                           'frozen archives',
                           'default_entries': default_pager_entries})
    output_objects.append({'object_type': 'frozenarchives',
                          'frozenarchives': frozenarchives})

    output_objects.append({'object_type': 'sectionheader', 'text':
                           'Additional Frozen Archives'})
    output_objects.append({'object_type': 'link',
                           'destination': 'adminfreeze.py',
                           'class': 'addlink',
                           'title': 'Specify a new frozen archive', 
                           'text': 'Create a new frozen archive'})

    return (output_objects, returnvalues.OK)
Exemplo n.º 11
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)
    action = accepted['action'][-1]
    req_list = accepted['req_id']
    job_list = accepted['job_id']
    lines = int(accepted['lines'][-1])

    meta = '''<meta http-equiv="refresh" content="%s" />
''' % configuration.sleep_secs
    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = '%s administration panel' % configuration.short_title
    title_entry['meta'] = meta

    # jquery support for tablesorter and confirmation on "remove"
    # table initially sorted by col. 9 (created)

    table_spec = {'table_id': 'accountreqtable', 'sort_order': '[[9,0]]'}
    (add_import, add_init, add_ready) = man_base_js(configuration,
                                                    [table_spec])
    title_entry['script']['advanced'] += add_import
    title_entry['script']['init'] += add_init
    title_entry['script']['ready'] += add_ready
    output_objects.append({
        'object_type': 'html_form',
        'text': man_base_html(configuration)
    })

    if not is_admin(client_id, configuration, logger):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'You must be an admin to access this control panel.'
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    html = ''
    if action and not action in grid_actions.keys() + accountreq_actions:
        output_objects.append({
            'object_type': 'error_text',
            'text': 'Invalid action: %s' % action
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)
    if action in grid_actions:
        msg = "%s" % grid_actions[action]
        if job_list:
            msg += ' %s' % ' '.join(job_list)
        msg += '\n'
        if not send_message_to_grid_script(msg, logger, configuration):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                '''Error sending %s message to grid_script.''' % action
            })
            status = returnvalues.SYSTEM_ERROR
    elif action in accountreq_actions:
        if action == "addaccountreq":
            for req_id in req_list:
                if accept_account_req(req_id, configuration):
                    output_objects.append({
                        'object_type':
                        'text',
                        'text':
                        'Accepted account request %s' % req_id
                    })
                else:
                    output_objects.append({
                        'object_type':
                        'error_text',
                        'text':
                        'Accept account request failed - details in log'
                    })
        elif action == "delaccountreq":
            for req_id in req_list:
                if delete_account_req(req_id, configuration):
                    output_objects.append({
                        'object_type':
                        'text',
                        'text':
                        'Deleted account request %s' % req_id
                    })
                else:
                    output_objects.append({
                        'object_type':
                        'error_text',
                        'text':
                        'Delete account request failed - details in log'
                    })

    show, drop = '', ''
    general = """
<h2>Server Status</h2>
<p class='importanttext'>
This page automatically refreshes every %s seconds.
</p>
<p>
You can see the current grid daemon status and server logs below. The buttons
provide access to e.g. managing the grid job queues.
</p>
<form method='get' action='migadmin.py'>
    <input type='hidden' name='action' value='' />
    <input type='submit' value='Show last log lines' />
    <input type='text' size='2' name='lines' value='%s' />
</form>
<br />
<form method='get' action='migadmin.py'>
    <input type='hidden' name='lines' value='%s' />
    <input type='hidden' name='action' value='reloadconfig' />
    <input type='submit' value='Reload Configuration' />
</form>
<br />
""" % (configuration.sleep_secs, lines, lines)
    show += """
<form method='get' action='migadmin.py'>
    <input type='hidden' name='lines' value='%s' />
    <input type='submit' value='Log Jobs' />
    <select name='action'>
""" % lines
    drop += """
<form method='get' action='migadmin.py'>
    <input type='hidden' name='lines' value='%s' />
    <input type='submit' value='Drop Job' />
    <select name='action'>
""" % lines
    for queue in ['queued', 'executing', 'done']:
        selected = ''
        if action.find(queue) != -1:
            selected = 'selected'
        show += "<option %s value='show%s'>%s</option>" % (selected, queue,
                                                           queue)
        drop += "<option %s value='drop%s'>%s</option>" % (selected, queue,
                                                           queue)
    show += """
    </select>
</form>
<br />
"""
    drop += """
    </select>
    <input type='text' size='20' name='job_id' value='' />
</form>
<br />
"""
    html += general
    html += show
    html += drop

    daemons = """
<div id='daemonstatus'>
"""
    daemon_names = []
    if configuration.site_enable_jobs:
        daemon_names += ['grid_script.py', 'grid_monitor.py', 'grid_sshmux.py']
    if configuration.site_enable_events:
        daemon_names.append('grid_events.py')
    # No need to run im_notify unless any im notify protocols are enabled
    if configuration.site_enable_imnotify and \
            [i for i in configuration.notify_protocols if i != 'email']:
        daemon_names.append('grid_imnotify.py')
    if configuration.site_enable_sftp:
        daemon_names.append('grid_sftp.py')
    if configuration.site_enable_davs:
        daemon_names.append('grid_webdavs.py')
    if configuration.site_enable_ftps:
        daemon_names.append('grid_ftps.py')
    if configuration.site_enable_openid:
        daemon_names.append('grid_openid.py')
    if configuration.site_enable_transfers:
        daemon_names.append('grid_transfers.py')
    if configuration.site_enable_crontab:
        daemon_names.append('grid_cron.py')
    if configuration.site_enable_seafile:
        daemon_names += [
            'seafile-controller', 'seaf-server', 'ccnet-server', 'seahub'
        ]
        if configuration.seafile_mount:
            daemon_names.append('seaf-fuse')
    if configuration.site_enable_sftp_subsys:
        daemon_names.append(
            '/sbin/sshd -f /etc/ssh/sshd_config-MiG-sftp-subsys')
    for proc in daemon_names:
        # NOTE: we use command list here to avoid shell requirement
        pgrep_proc = subprocess_popen(['pgrep', '-f', proc],
                                      stdout=subprocess_pipe,
                                      stderr=subprocess_stdout)
        pgrep_proc.wait()
        ps_out = pgrep_proc.stdout.read().strip()
        if pgrep_proc.returncode == 0:
            daemons += "<div class='status_online'>%s running (pid %s)</div>" \
                       % (proc, ps_out)
        else:
            daemons += "<div class='status_offline'>%s not running!</div>" % \
                       proc
    daemons += """</div>
<br />
"""
    html += daemons

    output_objects.append({
        'object_type': 'header',
        'text': 'Pending Certificate Requests'
    })

    (list_status, ret) = list_account_reqs(configuration)
    if not list_status:
        logger.error("%s: failed for '%s': %s" % (op_name, client_id, ret))
        output_objects.append({'object_type': 'error_text', 'text': ret})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    form_method = 'post'
    csrf_limit = get_csrf_limit(configuration)
    target_op = 'migadmin'
    csrf_token = make_csrf_token(configuration, form_method, target_op,
                                 client_id, csrf_limit)
    accountreqs = []
    for req_id in ret:
        (load_status, req_dict) = get_account_req(req_id, configuration)
        if not load_status:
            logger.error("%s: load failed for '%s': %s" %
                         (op_name, req_id, req_dict))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Could not read details for "%s"' % req_id
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)
        req_item = build_accountreqitem_object(configuration, req_dict)

        js_name = 'create%s' % req_id
        helper = html_post_helper(js_name, '%s.py' % target_op, {
            'action': 'addaccountreq',
            'req_id': req_id,
            csrf_field: csrf_token
        })
        output_objects.append({'object_type': 'html_form', 'text': helper})
        req_item['addaccountreqlink'] = {
            'object_type':
            'link',
            'destination':
            "javascript: confirmDialog(%s, '%s');" %
            (js_name, 'Really accept %s?' % req_id),
            'class':
            'addlink iconspace',
            'title':
            'Accept %s' % req_id,
            'text':
            ''
        }
        js_name = 'delete%s' % req_id
        helper = html_post_helper(js_name, '%s.py' % target_op, {
            'action': 'delaccountreq',
            'req_id': req_id,
            csrf_field: csrf_token
        })
        output_objects.append({'object_type': 'html_form', 'text': helper})
        req_item['delaccountreqlink'] = {
            'object_type':
            'link',
            'destination':
            "javascript: confirmDialog(%s, '%s');" %
            (js_name, 'Really remove %s?' % req_id),
            'class':
            'removelink iconspace',
            'title':
            'Remove %s' % req_id,
            'text':
            ''
        }
        accountreqs.append(req_item)

    output_objects.append({
        'object_type': 'table_pager',
        'entry_name': 'pending certificate/OpenID account requests',
        'default_entries': default_pager_entries
    })
    output_objects.append({
        'object_type': 'accountreqs',
        'accountreqs': accountreqs
    })

    log_path_list = []
    if os.path.isabs(configuration.logfile):
        log_path_list.append(configuration.logfile)
    else:
        log_path_list.append(
            os.path.join(configuration.log_dir, configuration.logfile))
    for log_path in log_path_list:
        html += '''
<h2>%s</h2>
<textarea class="fillwidth padspace" rows=%s readonly="readonly">
''' % (log_path, lines)
        log_lines = read_tail(log_path, lines, logger)
        html += ''.join(log_lines[-lines:])
        html += '''</textarea>
'''

    output_objects.append({'object_type': 'html_form', 'text': html})
    return (output_objects, returnvalues.OK)
Exemplo n.º 12
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)
    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)

    (stat, vgrid_list) = vgrid_list_vgrids(configuration)
    if not stat:
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'Error getting list of %s.' % \
                               configuration.site_vgrid_label})

    # Check if user wants advanced VGrid component links

    settings = load_settings(client_id, configuration)        
    collaboration_links = settings.get('SITE_COLLABORATION_LINKS', 'default')
    if not collaboration_links in configuration.site_collaboration_links or \
           collaboration_links == 'default':
        active_vgrid_links = configuration.site_default_vgrid_links
    elif collaboration_links == 'advanced':
        active_vgrid_links = configuration.site_advanced_vgrid_links

    # Iterate through vgrids and print details for each

    member_list = {'object_type': 'vgrid_list', 'vgrids': [],
                   'components': active_vgrid_links}
    if 'monitor' in active_vgrid_links:
        vgrid_list = [all_vgrids] + vgrid_list
    else:
        vgrid_list.remove(default_vgrid)
    for vgrid_name in vgrid_list:
        vgrid_obj = {'object_type': 'vgrid', 'name': vgrid_name}

        if vgrid_name == default_vgrid:

            # Everybody is member and allowed to see statistics, Noone
            # can own it or leave it. Do not add any page links.

            vgrid_obj['privatemonitorlink'] = {'object_type': 'link',
                                               'destination': 'showvgridmonitor.py?vgrid_name=%s'\
                                               % vgrid_name,
                                               'class': 'monitorlink',
                                               'title': 'View %s monitor' % vgrid_name, 
                                               'text': 'View'}
            vgrid_obj['memberlink'] = {'object_type': 'link',
                                       'destination':'',
                                       'class': 'infolink',
                                       'title': 'Every user is member of the %s %s' \
                                       % (default_vgrid,
                                          configuration.site_vgrid_label),
                                       'text': ''}
            vgrid_obj['administratelink'] = {'object_type': 'link',
                                       'destination':'',
                                       'class': 'infolink',
                                       'title': 'Nobody owns the %s %s' \
                                       % (default_vgrid,
                                          configuration.site_vgrid_label),
                                       'text': ''}
            member_list['vgrids'].append(vgrid_obj)
            continue
        elif vgrid_name == all_vgrids:

            # Only show global monitor link for all_vgrids, Noone
            # can own it or leave it. Do not add any page links.

            vgrid_obj['privatemonitorlink'] = {'object_type': 'link',
                                               'destination': 'showvgridmonitor.py?vgrid_name=%s'\
                                               % vgrid_name,
                                               'class': 'monitorlink',
                                               'title': 'View global monitor', 
                                               'text': 'View'}
            vgrid_obj['memberlink'] = {'object_type': 'link',
                                       'destination':'',
                                       'class': 'infolink',
                                       'title': 'Not a real %s - only for global monitor' % \
                                       configuration.site_vgrid_label,
                                       'text': ''}
            vgrid_obj['administratelink'] = {'object_type': 'link',
                                       'destination':'',
                                       'class': 'infolink',
                                       'title': 'Not a real %s - only for global monitor' % \
                                             configuration.site_vgrid_label,
                                       'text': ''}
            member_list['vgrids'].append(vgrid_obj)
            continue

        # links for everyone: public pages and membership request

        vgrid_obj['publicscmlink'] = {'object_type': 'link',
                'destination': '%s/vgridpublicscm/%s'\
                                       % (configuration.migserver_http_url,
                                          vgrid_name),
                                       'class': 'scmlink public',
                                       'title': 'Open %s public SCM' % \
                                       vgrid_name,
                                       'text': 'Open'}
        vgrid_obj['publictrackerlink'] = {'object_type': 'link',
                'destination': '%s/vgridpublictracker/%s'\
                                       % (configuration.migserver_http_url,
                                          vgrid_name),
                                       'class': 'trackerlink public',
                                       'title': 'Open %s public tracker' % \
                                       vgrid_name,
                                       'text': 'Open'}
        vgrid_obj['enterpubliclink'] = {'object_type': 'link',
                                        'destination':
                                        '%s/vgrid/%s/path/index.html' % \
                                        (configuration.migserver_http_url,
                                         vgrid_name),
                                        'class': 'urllink member',
                                        'title': 'View public %s web page' % \
                                        vgrid_name,
                                        'text': 'View'}

        # link to become member: overwritten later for members

        js_name = 'reqvgridmember%s' % hexlify(vgrid_name)
        helper = html_post_helper(js_name, 'sendrequestaction.py',
                                  {'vgrid_name': vgrid_name,
                                   'request_type': 'vgridmember',
                                   'request_text': ''})
        output_objects.append({'object_type': 'html_form', 'text': helper})
        vgrid_obj['memberlink'] = \
                                {'object_type': 'link',
                                 'destination':
                                 "javascript: confirmDialog(%s, '%s', '%s');"\
                                 % (js_name, "Request membership of " + \
                                    vgrid_name + ":<br/>" + \
                                    "\nPlease write a message to the owners (field below).",
                                    'request_text'),
                                 'class': 'addlink',
                                 'title': 'Request membership of %s' % \
                                 vgrid_name,
                                 'text': ''}

        # link to become owner: overwritten later for owners

        js_name = 'reqvgridowner%s' % hexlify(vgrid_name)
        helper = html_post_helper(js_name, 'sendrequestaction.py',
                                  {'vgrid_name': vgrid_name,
                                   'request_type': 'vgridowner',
                                   'request_text': ''})
        output_objects.append({'object_type': 'html_form', 'text': helper})
        vgrid_obj['administratelink'] = \
                                      {'object_type': 'link',
                                       'destination':
                                       "javascript: confirmDialog(%s, '%s', '%s');"\
                                       % (js_name, "Request ownership of " + \
                                          vgrid_name + ":<br/>" + \
                                          "\nPlease write a message to the owners (field below).",
                                          'request_text'),
                                       'class': 'addadminlink',
                                       'title': 'Request ownership of %s' % \
                                       vgrid_name,
                                       'text': ''}

        # members/owners are allowed to view private pages and monitor

        if vgrid_is_owner_or_member(vgrid_name, client_id, configuration):
            vgrid_obj['enterprivatelink'] = {'object_type': 'link',
                                             'destination':
                                             '../vgrid/%s/path/index.html' % \
                                             vgrid_name,
                                             'class': 'urllink owner',
                                             'title':
                                             'View private %s web page' % \
                                             vgrid_name, 
                                             'text': 'View'}
            vgrid_obj['sharedfolderlink'] = {'object_type': 'link',
                                             'destination':
                                             'fileman.py?path=%s/' % vgrid_name,
                                             'class': 'sharedfolderlink',
                                             'title': 'Open shared %s folder' \
                                             % vgrid_name, 
                                             'text': 'Open'}
            vgrid_obj['memberscmlink'] = {'object_type': 'link',
                                          'destination': '/vgridscm/%s' % \
                                          vgrid_name,
                                          'class': 'scmlink member',
                                          'title': 'View %s members scm' % \
                                          vgrid_name,
                                          'text': 'View'}
            vgrid_obj['membertrackerlink'] = {'object_type': 'link',
                                          'destination': '/vgridtracker/%s' % \
                                          vgrid_name,
                                          'class': 'trackerlink member',
                                          'title': 'View %s members tracker' % \
                                          vgrid_name,
                                          'text': 'View'}
            vgrid_obj['privateforumlink'] = {'object_type': 'link',
                                             'destination':
                                             'vgridforum.py?vgrid_name=%s' % \
                                             vgrid_name,
                                             'class': 'forumlink',
                                             'title': 'Open %s private forum' \
                                             % vgrid_name, 
                                               'text': 'Open'}
            vgrid_obj['privateworkflowslink'] = {'object_type': 'link',
                                             'destination':
                                             'vgridworkflows.py?vgrid_name=%s' % \
                                             vgrid_name,
                                             'class': 'workflowslink',
                                             'title': 'Open %s private workflows' \
                                             % vgrid_name, 
                                               'text': 'Open'}
            vgrid_obj['privatemonitorlink'] = {'object_type': 'link',
                                               'destination':
                                               'showvgridmonitor.py?vgrid_name=%s'\
                                               % vgrid_name,
                                               'class': 'monitorlink',
                                               'title': 'View %s monitor' % \
                                               vgrid_name, 
                                               'text': 'View'}

            # to leave this VGrid (remove ourselves). Note that we are
            # going to overwrite the link later for owners.

            js_name = 'rmvgridmember%s' % hexlify(vgrid_name)
            helper = html_post_helper(js_name, 'rmvgridmember.py',
                                      {'vgrid_name': vgrid_name,
                                       'cert_id': client_id})
            output_objects.append({'object_type': 'html_form', 'text': helper})
            vgrid_obj['memberlink'] = \
                                    {'object_type': 'link',
                                     'destination':
                                     "javascript: confirmDialog(%s, '%s');"\
                                     % (js_name, "Really leave " + vgrid_name + "?"),
                                     'class': 'removelink',
                                     'title': 'Leave %s members' % vgrid_name, 
                                     'text': ''}
            
        # owners are allowed to edit pages and administrate

        if vgrid_is_owner(vgrid_name, client_id, configuration):
            vgrid_obj['ownerscmlink'] = {'object_type': 'link',
                                         'destination': '/vgridownerscm/%s' % \
                                         vgrid_name,
                                         'class': 'scmlink owner',
                                         'title': 'View %s owners scm' % \
                                         vgrid_name,
                                         'text': 'View'}
            vgrid_obj['ownertrackerlink'] = {'object_type': 'link',
                                         'destination': '/vgridownertracker/%s' % \
                                         vgrid_name,
                                         'class': 'trackerlink owner',
                                         'title': 'View %s owners tracker' % \
                                         vgrid_name,
                                         'text': 'View'}

            # correct the link to leave the VGrid

            js_name = 'rmvgridowner%s' % hexlify(vgrid_name)
            helper = html_post_helper(js_name, 'rmvgridowner.py',
                                      {'vgrid_name': vgrid_name,
                                       'cert_id': client_id})
            output_objects.append({'object_type': 'html_form', 'text': helper})
            vgrid_obj['memberlink']['destination'] = \
                      "javascript: confirmDialog(%s,'%s');" % \
                      (js_name, "Really leave " + vgrid_name + "?")
            vgrid_obj['memberlink']['class'] = 'removeadminlink'
            vgrid_obj['memberlink']['title'] = 'Leave %s owners' % vgrid_name

            # add more links: administrate and edit pages

            vgrid_obj['administratelink'] = {'object_type': 'link',
                                             'destination': 'adminvgrid.py?vgrid_name=%s'\
                                             % vgrid_name,
                                             'class': 'adminlink',
                                             'title': 'Administrate %s' % vgrid_name,
                                             'text': ''}
            vgrid_obj['editprivatelink'] = {'object_type': 'link',
                                            'destination': 'fileman.py?path=private_base/%s/'\
                                            % vgrid_name,
                                            'class': 'editlink owner',
                                            'title': 'Edit private %s web page' % vgrid_name,
                                            'text': 'Edit'}
            vgrid_obj['editpubliclink'] = {'object_type': 'link',
                                           'destination': 'fileman.py?path=public_base/%s/'\
                                           % vgrid_name,
                                           'class': 'editlink member',
                                           'title': 'Edit public %s web page' % vgrid_name,
                                           'text': 'Edit'}


        member_list['vgrids'].append(vgrid_obj)

    title_entry = find_entry(output_objects, 'title')
    label = "%ss" % configuration.site_vgrid_label
    # Append VGrid note if custom
    if label != 'VGrid':
        label += ' (i.e. VGrids)'
    title_entry['text'] = '%s administration' % label

    # jquery support for tablesorter and confirmation on "leave":

    title_entry['style'] = themed_styles(configuration)
    title_entry['javascript'] = '''
<script type="text/javascript" src="/images/js/jquery.js"></script>
<script type="text/javascript" src="/images/js/jquery.tablesorter.js"></script>
<script type="text/javascript" src="/images/js/jquery.tablesorter.pager.js"></script>
<script type="text/javascript" src="/images/js/jquery.tablesorter.widgets.js"></script>
<script type="text/javascript" src="/images/js/jquery-ui.js"></script>
<script type="text/javascript" src="/images/js/jquery.confirm.js"></script>

<script type="text/javascript" >

$(document).ready(function() {

          // init confirmation dialog
          $( "#confirm_dialog" ).dialog(
              // see http://jqueryui.com/docs/dialog/ for options
              { autoOpen: false,
                modal: true, closeOnEscape: true,
                width: 500,
                buttons: {
                   "Cancel": function() { $( "#" + name ).dialog("close"); }
                }
              });

          // table initially sorted by col. 1 (admin), then 2 (member), then 0 (name)
          var sortOrder = [[1,1],[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;
          }

          $("#vgridtable").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': label})
    output_objects.append({'object_type': 'text', 'text'
                          : '''
%ss share files, a number of collaboration tools and resources. Members can access web pages, files, tools and resources. Owners can additionally edit pages, as well as add and remove members or resources.
''' % configuration.site_vgrid_label
                       })

    if configuration.site_vgrid_label != 'VGrid':
        output_objects.append({'object_type': 'text', 'text'
                          : """Please note that for historical reasons %ss are
also referred to as VGrids in some contexts.""" % \
                               configuration.site_vgrid_label})

    output_objects.append({'object_type': 'sectionheader', 'text'
                          : '%ss managed on this server' % \
                           configuration.site_vgrid_label})
    output_objects.append({'object_type': 'table_pager', 'entry_name': '%ss' % \
                           configuration.site_vgrid_label,
                           'default_entries': default_pager_entries})
    output_objects.append(member_list)

    user_map = get_full_user_map(configuration)
    user_dict = user_map.get(client_id, None)
    # Optional limitation of create vgrid permission
    if user_dict and vgrid_create_allowed(configuration, user_dict):
        output_objects.append({'object_type': 'sectionheader', 'text'
                               : 'Additional %ss' % \
                               configuration.site_vgrid_label})

        output_objects.append(
            {'object_type': 'text', 'text':
             '''Please enter a name for the new %(label)s to add, using slashes to
 specify nesting. I.e. if you own a %(label)s called ABC, you can create a
 sub-%(label)s called DEF by entering ABC/DEF below.''' % \
             {'label': configuration.site_vgrid_label}})
        output_objects.append({'object_type': 'html_form', 'text':
                                '''<form method="post" action="createvgrid.py">
    <input type="text" size=40 name="vgrid_name" />
    <input type="hidden" name="output_format" value="html" />
    <input type="submit" value="Create %s" />
    </form>
 ''' % configuration.site_vgrid_label})

    output_objects.append({'object_type': 'sectionheader', 'text'
                               : 'Request Access to %ss' % \
                               configuration.site_vgrid_label})

    output_objects.append(
        {'object_type': 'text', 'text':
         '''You can request access to %(label)ss using the individual plus-icons above directly or by entering the name of the %(label)s to request access to, what kind of access and an optional message to the admins below''' % \
             {'label': configuration.site_vgrid_label}})
    output_objects.append({'object_type': 'html_form', 'text':
                           '''<form method="post" action="sendrequestaction.py">
    <input type="text" size=40 name="vgrid_name" />
    <select name="request_type">
        <option value="vgridmember">membership</option> 
        <option value="vgridowner">ownership</option>
    </select>
    <input type="text" size=50 name="request_text" />
    <input type="hidden" name="output_format" value="html" />
    <input type="submit" value="Request %s access" />
    </form>
 ''' % configuration.site_vgrid_label})

    return (output_objects, status)
Exemplo n.º 13
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)
Exemplo n.º 14
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)
    status = returnvalues.OK
    defaults = signature()[1]
    title_entry = find_entry(output_objects, 'title')
    label = "%s" % configuration.site_vgrid_label
    title_entry['text'] = "%s Management" % label
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
    )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    operation = accepted['operation'][-1]
    caching = (accepted['caching'][-1].lower() in ('true', 'yes'))

    if not operation in allowed_operations:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''Operation must be one of %s.''' % ', '.join(allowed_operations)
        })
        return (output_objects, returnvalues.OK)

    logger.info("%s %s begin for %s" % (op_name, operation, client_id))
    vgrid_items, active_vgrid_links = [], []
    member_list = {
        'object_type': 'vgrid_list',
        'vgrids': vgrid_items,
        'components': active_vgrid_links
    }

    # Check if user wants advanced VGrid component links

    user_settings = title_entry.get('user_settings', {})
    collaboration_links = user_settings.get('SITE_COLLABORATION_LINKS',
                                            'default')
    if not collaboration_links in configuration.site_collaboration_links or \
            collaboration_links == 'default':
        active_vgrid_links += configuration.site_default_vgrid_links
    elif collaboration_links == 'advanced':
        active_vgrid_links += configuration.site_advanced_vgrid_links

    # General fill helpers including CSRF fields

    form_method = 'post'
    csrf_limit = get_csrf_limit(configuration)
    fill_helpers = {
        'vgrid_label': label,
        'form_method': form_method,
        'csrf_field': csrf_field,
        'csrf_limit': csrf_limit
    }

    if operation in show_operations:

        # jquery support for tablesorter and confirmation on request and leave
        # table initially sorted by col. 2 (admin), then 3 (member), then 0 (name)

        # NOTE: We distinguish between caching on page load and forced refresh
        refresh_helper = 'ajax_vgridman("%s", %s, %%s)'
        refresh_call = refresh_helper % (label, active_vgrid_links)
        table_spec = {
            'table_id': 'vgridtable',
            'sort_order': '[[2,1],[3,1],[0,0]]',
            'refresh_call': refresh_call % 'false'
        }
        (add_import, add_init,
         add_ready) = man_base_js(configuration, [table_spec])
        if operation == "show":
            add_ready += '%s;' % (refresh_call % 'true')
        title_entry['script']['advanced'] += add_import
        title_entry['script']['init'] += add_init
        title_entry['script']['ready'] += add_ready
        output_objects.append({
            'object_type': 'html_form',
            'text': man_base_html(configuration)
        })

        # Append VGrid alias note if custom
        if label != 'VGrid':
            long_label = '%ss (i.e. VGrids)' % label
        else:
            long_label = "%ss" % label

        output_objects.append({
            'object_type': 'header',
            'text': "%s" % long_label
        })
        output_objects.append({
            'object_type':
            'text',
            'text':
            '''%ss share files, a number of collaboration
tools and resources. Members can access web pages, files, tools and resources.
Owners can additionally edit pages, as well as add and remove members or
resources.''' % label
        })

        if label != 'VGrid':
            output_objects.append({
                'object_type':
                'text',
                'text':
                """Please note that for historical reasons
%ss are also referred to as VGrids in some contexts.""" % label
            })

        output_objects.append({
            'object_type': 'sectionheader',
            'text': '%ss managed on this server' % label
        })

        # Helper forms for requests and removes

        for post_type in ["vgridowner", "vgridmember"]:
            target_op = 'sendrequestaction'
            csrf_token = make_csrf_token(configuration, form_method, target_op,
                                         client_id, csrf_limit)
            helper = html_post_helper(
                'req%s' % post_type, '%s.py' % target_op, {
                    'vgrid_name': '__DYNAMIC__',
                    'request_type': post_type,
                    'request_text': '',
                    csrf_field: csrf_token
                })
            output_objects.append({'object_type': 'html_form', 'text': helper})
        for post_type in ["vgridowner", "vgridmember"]:
            target_op = 'rm%s' % post_type
            csrf_token = make_csrf_token(configuration, form_method, target_op,
                                         client_id, csrf_limit)
            helper = html_post_helper(
                target_op, '%s.py' % target_op, {
                    'vgrid_name': '__DYNAMIC__',
                    'cert_id': client_id,
                    csrf_field: csrf_token
                })
            output_objects.append({'object_type': 'html_form', 'text': helper})

        output_objects.append({
            'object_type': 'table_pager',
            'entry_name': '%ss' % label,
            'default_entries': default_pager_entries
        })

    if operation in list_operations:
        logger.info("get vgrid map with caching %s" % caching)
        vgrid_map = get_vgrid_map(configuration, caching=caching)
        member_list['pending_updates'] = False
        if caching:
            modified_vgrids, _ = check_vgrids_modified(configuration)
            if modified_vgrids:
                logger.info("pending cache updates: %s" % modified_vgrids)
                member_list['pending_updates'] = True
            else:
                logger.info("no pending cache updates")

        vgrid_list = vgrid_map[VGRIDS].keys()

        # Iterate through vgrids and print details for each

        if 'monitor' in active_vgrid_links:
            vgrid_list = [all_vgrids] + vgrid_list
        else:
            vgrid_list.remove(default_vgrid)
        # User vgrid_list here to include default and all mangling above
        for vgrid_name in vgrid_list:
            vgrid_dict = vgrid_map[VGRIDS].get(vgrid_name, {})
            settings_dict = dict(vgrid_dict.get(SETTINGS, []))
            # Mark and show hidden vgrids if owner or member and hide otherwise
            view_icon, hidden_status = "infolink", " "
            if settings_dict.get('hidden', False):
                if client_id in vgrid_dict[OWNERS] + vgrid_dict[MEMBERS]:
                    logger.debug("show hidden vgrid %s for participant" %
                                 vgrid_name)
                    view_icon, hidden_status = "shadeinfolink", " hidden "
                else:
                    logger.debug("skip hidden vgrid %s" % vgrid_name)
                    continue
            vgrid_obj = {'object_type': 'vgrid', 'name': vgrid_name}

            if vgrid_name == default_vgrid:

                # Everybody is member and allowed to see statistics, Noone
                # can own it or leave it. Do not add any page links.

                vgrid_obj['privatemonitorlink'] = {
                    'object_type': 'link',
                    'destination':
                    'showvgridmonitor.py?vgrid_name=%s' % vgrid_name,
                    'class': 'monitorlink iconspace',
                    'title': 'View %s monitor' % vgrid_name,
                    'text': 'View'
                }
                vgrid_obj['memberlink'] = {
                    'object_type':
                    'link',
                    'destination':
                    '',
                    'class':
                    'infolink iconspace',
                    'title':
                    'Every user is member of the %s %s' %
                    (default_vgrid, label),
                    'text':
                    ''
                }
                vgrid_obj['administratelink'] = {
                    'object_type': 'link',
                    'destination': '',
                    'class': 'infolink iconspace',
                    'title': 'Nobody owns the %s %s' % (default_vgrid, label),
                    'text': ''
                }
                vgrid_obj['viewvgridlink'] = {
                    'object_type': 'link',
                    'destination': 'viewvgrid.py?vgrid_name=%s' % vgrid_name,
                    'class': 'infolink iconspace',
                    'title':
                    'View details for the %s %s' % (default_vgrid, label),
                    'text': ''
                }
                vgrid_items.append(vgrid_obj)
                continue
            elif vgrid_name == all_vgrids:

                # Only show global monitor link for all_vgrids, Noone
                # can own it or leave it. Do not add any page links.

                vgrid_obj['privatemonitorlink'] = {
                    'object_type': 'link',
                    'destination':
                    'showvgridmonitor.py?vgrid_name=%s' % vgrid_name,
                    'class': 'monitorlink iconspace',
                    'title': 'View global monitor',
                    'text': 'View'
                }
                vgrid_obj['memberlink'] = {
                    'object_type': 'link',
                    'destination': '',
                    'class': 'infolink iconspace',
                    'title': 'Not a real %s - only for global monitor' % label,
                    'text': ''
                }
                vgrid_obj['administratelink'] = {
                    'object_type': 'link',
                    'destination': '',
                    'class': '',
                    'title': '',
                    'text': ''
                }
                vgrid_obj['viewvgridlink'] = {
                    'object_type': 'link',
                    'destination': '',
                    'class': 'infolink iconspace',
                    'title': 'Not a real %s - only for global monitor' % label,
                    'text': ''
                }
                vgrid_items.append(vgrid_obj)
                continue

            # links for everyone: public pages and membership request

            vgrid_obj['publicscmlink'] = {
                'object_type':
                'link',
                'destination':
                '%s/vgridpublicscm/%s' %
                (configuration.migserver_http_url, vgrid_name),
                'class':
                'scmlink public iconspace',
                'title':
                'Open %s public SCM' % vgrid_name,
                'text':
                'Open'
            }
            vgrid_obj['publictrackerlink'] = {
                'object_type':
                'link',
                'destination':
                '%s/vgridpublictracker/%s' %
                (configuration.migserver_http_url, vgrid_name),
                'class':
                'trackerlink public iconspace',
                'title':
                'Open %s public tracker' % vgrid_name,
                'text':
                'Open'
            }
            vgrid_obj['enterpubliclink'] = {
                'object_type':
                'link',
                'destination':
                '%s/vgrid/%s/path/index.html' %
                (configuration.migserver_http_url, vgrid_name),
                'class':
                'urllink member iconspace',
                'title':
                'View public %s web page' % vgrid_name,
                'text':
                'View'
            }

            # Link to show vgrid details

            vgrid_obj['viewvgridlink'] = \
                {'object_type': 'link',
                 'destination': 'viewvgrid.py?vgrid_name=%s' %
                 vgrid_name,
                 'class': '%s iconspace' % view_icon,
                 'title': 'View details for the %s%s%s'
                 % (vgrid_name, hidden_status, label),
                 'text': ''}

            # link to become member: overwritten later for members

            vgrid_obj['memberlink'] = {
                'object_type':
                'link',
                'destination':
                "javascript: confirmDialog(%s, '%s', '%s', %s);" %
                ('reqvgridmember', "Request membership of " + vgrid_name +
                 ":<br/>\nPlease write a message to the owners (field below).",
                 'request_text', "{vgrid_name: '%s'}" % vgrid_name),
                'class':
                'addlink iconspace',
                'title':
                'Request membership of %s' % vgrid_name,
                'text':
                ''
            }

            # link to become owner: overwritten later for owners

            vgrid_obj['administratelink'] = {
                'object_type':
                'link',
                'destination':
                "javascript: confirmDialog(%s, '%s', '%s', %s);" %
                ('reqvgridowner', "Request ownership of " + vgrid_name +
                 ":<br/>\nPlease write a message to the owners (field below).",
                 'request_text', "{vgrid_name: '%s'}" % vgrid_name),
                'class':
                'addadminlink iconspace',
                'title':
                'Request ownership of %s' % vgrid_name,
                'text':
                ''
            }

            # members/owners are allowed to view private pages and monitor

            if client_id in vgrid_dict[OWNERS] + vgrid_dict[MEMBERS]:
                vgrid_obj['enterprivatelink'] = {
                    'object_type': 'link',
                    'destination': '../vgrid/%s/path/index.html' % vgrid_name,
                    'class': 'urllink owner iconspace',
                    'title': 'View private %s web page' % vgrid_name,
                    'text': 'View'
                }
                vgrid_obj['sharedfolderlink'] = {
                    'object_type': 'link',
                    'destination': 'fileman.py?path=%s/' % vgrid_name,
                    'class': 'sharedfolderlink iconspace',
                    'title': 'Open shared %s folder' % vgrid_name,
                    'text': 'Open'
                }
                vgrid_obj['memberscmlink'] = {
                    'object_type': 'link',
                    'destination': '/vgridscm/%s' % vgrid_name,
                    'class': 'scmlink member iconspace',
                    'title': 'View %s members scm' % vgrid_name,
                    'text': 'View'
                }
                vgrid_obj['membertrackerlink'] = {
                    'object_type': 'link',
                    'destination': '/vgridtracker/%s' % vgrid_name,
                    'class': 'trackerlink member iconspace',
                    'title': 'View %s members tracker' % vgrid_name,
                    'text': 'View'
                }
                vgrid_obj['privateforumlink'] = {
                    'object_type': 'link',
                    'destination': 'vgridforum.py?vgrid_name=%s' % vgrid_name,
                    'class': 'forumlink iconspace',
                    'title': 'Open %s private forum' % vgrid_name,
                    'text': 'Open'
                }
                vgrid_obj['privateworkflowslink'] = {
                    'object_type': 'link',
                    'destination':
                    'vgridworkflows.py?vgrid_name=%s' % vgrid_name,
                    'class': 'workflowslink iconspace',
                    'title': 'Open %s private workflows' % vgrid_name,
                    'text': 'Open'
                }
                vgrid_obj['privatemonitorlink'] = {
                    'object_type': 'link',
                    'destination':
                    'showvgridmonitor.py?vgrid_name=%s' % vgrid_name,
                    'class': 'monitorlink iconspace',
                    'title': 'View %s monitor' % vgrid_name,
                    'text': 'View'
                }

                # to leave this VGrid (remove ourselves). Note that we are
                # going to overwrite the link later for owners.

                vgrid_obj['memberlink'].update({
                    'destination':
                    "javascript: confirmDialog(%s, '%s', %s, %s);" %
                    ('rmvgridmember', "Really leave " + vgrid_name + "?",
                     'undefined', "{vgrid_name: '%s'}" % vgrid_name),
                    'class':
                    'removelink iconspace',
                    'title':
                    'Leave %s members' % vgrid_name,
                })

            # owners are allowed to edit pages and administrate

            if client_id in vgrid_dict[OWNERS]:
                vgrid_obj['ownerscmlink'] = {
                    'object_type': 'link',
                    'destination': '/vgridownerscm/%s' % vgrid_name,
                    'class': 'scmlink owner iconspace',
                    'title': 'View %s owners scm' % vgrid_name,
                    'text': 'View'
                }
                vgrid_obj['ownertrackerlink'] = {
                    'object_type': 'link',
                    'destination': '/vgridownertracker/%s' % vgrid_name,
                    'class': 'trackerlink owner iconspace',
                    'title': 'View %s owners tracker' % vgrid_name,
                    'text': 'View'
                }

                # correct the link to leave the VGrid

                vgrid_obj['memberlink'].update({
                    'destination':
                    "javascript: confirmDialog(%s, '%s', %s, %s);" %
                    ('rmvgridowner', "Really leave " + vgrid_name + "?",
                     'undefined', "{vgrid_name: '%s'}" % vgrid_name),
                    'class':
                    'removeadminlink iconspace',
                    'title':
                    'Leave %s owners' % vgrid_name
                })

                # add more links: administrate and edit pages

                vgrid_obj['administratelink'] = {
                    'object_type': 'link',
                    'destination': 'adminvgrid.py?vgrid_name=%s' % vgrid_name,
                    'class': 'adminlink iconspace',
                    'title': 'Administrate %s' % vgrid_name,
                    'text': ''
                }
                vgrid_obj['editprivatelink'] = {
                    'object_type': 'link',
                    'destination':
                    'fileman.py?path=private_base/%s/' % vgrid_name,
                    'class': 'editlink owner iconspace',
                    'title': 'Edit private %s web page' % vgrid_name,
                    'text': 'Edit'
                }
                vgrid_obj['editpubliclink'] = {
                    'object_type': 'link',
                    'destination':
                    'fileman.py?path=public_base/%s/' % vgrid_name,
                    'class': 'editlink member iconspace',
                    'title': 'Edit public %s web page' % vgrid_name,
                    'text': 'Edit'
                }

            vgrid_items.append(vgrid_obj)

    if operation == "show":
        # insert dummy placeholder to build table
        vgrid_obj = {'object_type': 'vgrid', 'name': default_vgrid}
        for field in active_vgrid_links:
            vgrid_obj[field] = ''
        vgrid_items.append(vgrid_obj)

    output_objects.append(member_list)

    if operation in show_operations:
        user_map = get_full_user_map(configuration)
        user_dict = user_map.get(client_id, None)
        # Optional limitation of create vgrid permission
        if user_dict and vgrid_create_allowed(configuration, user_dict):
            output_objects.append({
                'object_type': 'sectionheader',
                'text': 'Additional %ss' % label
            })

            output_objects.append({
                'object_type':
                'text',
                'text':
                '''Please enter a name for the new %(vgrid_label)s to add,
using slashes to specify nesting. I.e. if you own a %(vgrid_label)s called ABC,
you can create a sub-%(vgrid_label)s called DEF by entering ABC/DEF below.
''' % fill_helpers
            })

            target_op = 'createvgrid'
            csrf_token = make_csrf_token(configuration, form_method, target_op,
                                         client_id, csrf_limit)
            fill_helpers.update({
                'target_op': target_op,
                'csrf_token': csrf_token
            })
            output_objects.append({
                'object_type':
                'html_form',
                'text':
                '''
        <form method="%(form_method)s" action="%(target_op)s.py">
        <input type="hidden" name="%(csrf_field)s" value="%(csrf_token)s" />
        <input class="p60width" type="text" name="vgrid_name" required 
        pattern="[a-zA-Z0-9 /_.-]*"
        title="unique name of ASCII letters and digits separated only by underscores, periods, spaces and hyphens. Slashes are additionally allowed when creating nested sub-%(vgrid_label)ss" />
        <input type="hidden" name="output_format" value="html" />
        <input type="submit" value="Create %(vgrid_label)s" />
        </form>
     ''' % fill_helpers
            })

        output_objects.append({
            'object_type': 'sectionheader',
            'text': 'Request Access to %ss' % label
        })

        output_objects.append({
            'object_type':
            'text',
            'text':
            '''You can request access to %(vgrid_label)ss using the individual
plus-icons above directly or by entering the name of the %(vgrid_label)s to
request access to, what kind of access and an optional message to the admins
below''' % fill_helpers
        })
        target_op = 'sendrequestaction'
        csrf_token = make_csrf_token(configuration, form_method, target_op,
                                     client_id, csrf_limit)
        fill_helpers.update({'target_op': target_op, 'csrf_token': csrf_token})
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            '''
        <form method="%(form_method)s" action="%(target_op)s.py">
        <input type="hidden" name="%(csrf_field)s" value="%(csrf_token)s" />
        <input class="p60width" type="text" name="vgrid_name" required 
        pattern="[a-zA-Z0-9 /_.-]*"
        title="the name of an existing %(vgrid_label)s" />
        <select class="styled-select html-select" name="request_type">
            <option value="vgridmember">membership</option> 
            <option value="vgridowner">ownership</option>
        </select>
        <br/>
        <input class="p60width" type="text" name="request_text" required />
        <input type="hidden" name="output_format" value="html" />
        <input type="submit" value="Request %(vgrid_label)s access" />
        </form>
    ''' % fill_helpers
        })

    logger.info("%s %s end for %s" % (op_name, operation, client_id))
    return (output_objects, status)
Exemplo n.º 15
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)
    defaults = signature()[1]
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
    )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    action = accepted['action'][-1]
    share_id = accepted['share_id'][-1]
    path = accepted['path'][-1]
    read_access = accepted['read_access'][-1].lower() in enabled_strings
    write_access = accepted['write_access'][-1].lower() in enabled_strings
    expire = accepted['expire'][-1]
    # Merge and split invite to make sure 'a@b, c@d' entries are handled
    invite_list = ','.join(accepted['invite']).split(',')
    invite_list = [i for i in invite_list if i]
    invite_msg = accepted['msg']

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'Share Link'

    # jquery support for tablesorter and confirmation on delete/redo:
    # table initially sorted by 5, 4 reversed (active first and in growing age)

    table_spec = {'table_id': 'sharelinkstable', 'sort_order': '[[5,1],[4,1]]'}
    (add_import, add_init, add_ready) = man_base_js(configuration,
                                                    [table_spec],
                                                    {'width': 600})
    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)
    })

    header_entry = {'object_type': 'header', 'text': 'Manage share links'}
    output_objects.append(header_entry)

    if not configuration.site_enable_sharelinks:
        output_objects.append({
            'object_type':
            'text',
            'text':
            '''
Share links are disabled on this site.
Please contact the site admins %s if you think they should be enabled.
''' % configuration.admin_email
        })
        return (output_objects, returnvalues.OK)

    logger.info('sharelink %s from %s' % (action, client_id))
    logger.debug('sharelink from %s: %s' % (client_id, accepted))

    if not action in valid_actions:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'Invalid action "%s" (supported: %s)' %
            (action, ', '.join(valid_actions))
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    if action in post_actions:
        if not safe_handler(configuration, 'post', op_name, client_id,
                            get_csrf_limit(configuration), accepted):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                '''Only accepting
                CSRF-filtered POST requests to prevent unintended updates'''
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

    (load_status, share_map) = load_share_links(configuration, client_id)
    if not load_status:
        share_map = {}

    form_method = 'post'
    csrf_limit = get_csrf_limit(configuration)
    target_op = 'sharelink'
    csrf_token = make_csrf_token(configuration, form_method, target_op,
                                 client_id, csrf_limit)
    if action in get_actions:
        if action == "show":
            # Table columns to skip
            skip_list = ['owner', 'single_file', 'expire']
            sharelinks = []
            for (saved_id, share_dict) in share_map.items():
                share_item = build_sharelinkitem_object(
                    configuration, share_dict)
                js_name = 'delete%s' % hexlify(saved_id)
                helper = html_post_helper(
                    js_name, '%s.py' % target_op, {
                        'share_id': saved_id,
                        'action': 'delete',
                        csrf_field: csrf_token
                    })
                output_objects.append({
                    'object_type': 'html_form',
                    'text': helper
                })
                share_item['delsharelink'] = {
                    'object_type':
                    'link',
                    'destination':
                    "javascript: confirmDialog(%s, '%s');" %
                    (js_name, 'Really remove %s?' % saved_id),
                    'class':
                    'removelink iconspace',
                    'title':
                    'Remove share link %s' % saved_id,
                    'text':
                    ''
                }
                sharelinks.append(share_item)

            # Display share links and form to add new ones

            output_objects.append({
                'object_type': 'sectionheader',
                'text': 'Share Links'
            })
            output_objects.append({
                'object_type': 'table_pager',
                'entry_name': 'share links',
                'default_entries': default_pager_entries
            })
            output_objects.append({
                'object_type': 'sharelinks',
                'sharelinks': sharelinks,
                'skip_list': skip_list
            })

            output_objects.append({
                'object_type': 'html_form',
                'text': '<br/>'
            })
            output_objects.append({
                'object_type': 'sectionheader',
                'text': 'Create Share Link'
            })
            submit_button = '''<span>
    <input type=submit value="Create share link" />
    </span>'''
            sharelink_html = create_share_link_form(configuration, client_id,
                                                    'html', submit_button,
                                                    csrf_token)
            output_objects.append({
                'object_type': 'html_form',
                'text': sharelink_html
            })
        elif action == "edit":
            header_entry['text'] = 'Edit Share Link'
            share_dict = share_map.get(share_id, {})
            if not share_dict:
                output_objects.append({
                    'object_type':
                    'error_text',
                    'text':
                    'existing share link is required for edit'
                })
                return (output_objects, returnvalues.CLIENT_ERROR)

            output_objects.append({
                'object_type':
                'html_form',
                'text':
                '''
<p>
Here you can send invitations for your share link %(share_id)s to one or more
comma-separated recipients.
</p>
                                   ''' % share_dict
            })
            sharelinks = []
            share_item = build_sharelinkitem_object(configuration, share_dict)
            saved_id = share_item['share_id']
            js_name = 'delete%s' % hexlify(saved_id)
            helper = html_post_helper(js_name, '%s.py' % target_op, {
                'share_id': saved_id,
                'action': 'delete',
                csrf_field: csrf_token
            })
            output_objects.append({'object_type': 'html_form', 'text': helper})
            # Hide link to self
            del share_item['editsharelink']
            share_item['delsharelink'] = {
                'object_type':
                'link',
                'destination':
                "javascript: confirmDialog(%s, '%s');" %
                (js_name, 'Really remove %s?' % saved_id),
                'class':
                'removelink iconspace',
                'title':
                'Remove share link %s' % saved_id,
                'text':
                ''
            }
            sharelinks.append(share_item)
            output_objects.append({
                'object_type': 'sharelinks',
                'sharelinks': sharelinks
            })
            submit_button = '''<span>
    <input type=submit value="Send invitation(s)" />
    </span>'''
            sharelink_html = invite_share_link_form(configuration, client_id,
                                                    share_dict, 'html',
                                                    submit_button, csrf_token)
            output_objects.append({
                'object_type': 'html_form',
                'text': sharelink_html
            })
            output_objects.append({
                'object_type': 'link',
                'destination': 'sharelink.py',
                'text': 'Return to share link overview'
            })

        return (output_objects, returnvalues.OK)
    elif action in post_actions:
        share_dict = share_map.get(share_id, {})
        if not share_dict and action != 'create':
            logger.warning('%s tried to %s missing or not owned link %s!' %
                           (client_id, action, share_id))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                '%s requires existing share link' % action
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

        share_path = share_dict.get('path', path)

        # 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

        rel_share_path = share_path.lstrip(os.sep)
        # IMPORTANT: path must be expanded to abs for proper chrooting
        abs_path = os.path.abspath(os.path.join(base_dir, rel_share_path))
        relative_path = abs_path.replace(base_dir, '')
        real_path = os.path.realpath(abs_path)
        single_file = os.path.isfile(real_path)
        vgrid_name = in_vgrid_share(configuration, abs_path)

        if action == 'delete':
            header_entry['text'] = 'Delete Share Link'
            (save_status, _) = delete_share_link(share_id, client_id,
                                                 configuration, share_map)
            if save_status and vgrid_name:
                logger.debug("del vgrid sharelink pointer %s" % share_id)
                (del_status,
                 del_msg) = vgrid_remove_sharelinks(configuration, vgrid_name,
                                                    [share_id], 'share_id')
                if not del_status:
                    logger.error("del vgrid sharelink pointer %s failed: %s" %
                                 (share_id, del_msg))
                    return (False, share_map)
            desc = "delete"
        elif action == "update":
            header_entry['text'] = 'Update Share Link'
            # Try to point replies to client_id email
            client_email = extract_field(client_id, 'email')
            if invite_list:
                invites = share_dict.get('invites', []) + invite_list
                invites_uniq = list(set([i for i in invites if i]))
                invites_uniq.sort()
                share_dict['invites'] = invites_uniq
                auto_msg = invite_share_link_message(configuration, client_id,
                                                     share_dict, 'html')
                msg = '\n'.join(invite_msg)
                # Now send request to all targets in turn
                threads = []
                for target in invite_list:
                    job_dict = {
                        'NOTIFY': [target.strip()],
                        'JOB_ID': 'NOJOBID',
                        'USER_CERT': client_id,
                        'EMAIL_SENDER': client_email
                    }

                    logger.debug('invite %s to %s' % (target, share_id))
                    threads.append(
                        notify_user_thread(
                            job_dict,
                            [auto_msg, msg],
                            'INVITESHARE',
                            logger,
                            '',
                            configuration,
                        ))

                # Try finishing delivery but do not block forever on one message
                notify_done = [False for _ in threads]
                for _ in range(3):
                    for i in range(len(invite_list)):
                        if not notify_done[i]:
                            logger.debug('check done %s' % invite_list[i])
                            notify = threads[i]
                            notify.join(3)
                            notify_done[i] = not notify.isAlive()
                notify_sent, notify_failed = [], []
                for i in range(len(invite_list)):
                    if notify_done[i]:
                        notify_sent.append(invite_list[i])
                    else:
                        notify_failed.append(invite_list[i])
                logger.debug('notify sent %s, failed %s' %
                             (notify_sent, notify_failed))
                if notify_failed:
                    output_objects.append({
                        'object_type':
                        'html_form',
                        'text':
                        '''
<p>Failed to send invitation to %s</p>''' % ', '.join(notify_failed)
                    })
                if notify_sent:
                    output_objects.append({
                        'object_type':
                        'html_form',
                        'text':
                        '''<p>Invitation sent to %s</p>
<textarea class="fillwidth padspace" rows="%d" readonly="readonly">
%s
%s
</textarea>
                                            ''' %
                        (', '.join(notify_sent),
                         (auto_msg + msg).count('\n') + 3, auto_msg, msg)
                    })
            if expire:
                share_dict['expire'] = expire
            (save_status, _) = update_share_link(share_dict, client_id,
                                                 configuration, share_map)
            desc = "update"
        elif action == "create":
            header_entry['text'] = 'Create Share Link'
            if not read_access and not write_access:
                output_objects.append({
                    'object_type':
                    'error_text',
                    'text':
                    'No access set - please select read, write or both'
                })
                return (output_objects, returnvalues.CLIENT_ERROR)
            # NOTE: check path here as relative_path is empty for path='/'
            if not path:
                output_objects.append({
                    'object_type': 'error_text',
                    'text': 'No path provided!'
                })
                return (output_objects, returnvalues.CLIENT_ERROR)
            # We refuse sharing of entire home for security reasons
            elif not valid_user_path(
                    configuration, abs_path, base_dir, allow_equal=False):
                logger.warning('%s tried to %s restricted path %s ! (%s)' %
                               (client_id, action, abs_path, path))
                output_objects.append({
                    'object_type':
                    'error_text',
                    'text':
                    '''Illegal path "%s":
you can only share your own data, and not your entire home direcory.''' % path
                })
                return (output_objects, returnvalues.CLIENT_ERROR)
            elif not os.path.exists(abs_path):
                output_objects.append({
                    'object_type':
                    'error_text',
                    'text':
                    'Provided path "%s" does not exist!' % path
                })
                return (output_objects, returnvalues.CLIENT_ERROR)
            # Refuse sharing of (mainly auth) dot dirs in root of user home
            elif real_path.startswith(os.path.join(base_dir, '.')):
                output_objects.append({
                    'object_type':
                    'error_text',
                    'text':
                    'Provided path "%s" cannot be shared for security reasons'
                    % path
                })
                return (output_objects, returnvalues.CLIENT_ERROR)
            elif single_file and write_access:
                output_objects.append({
                    'object_type':
                    'error_text',
                    'text':
                    '''Individual files
cannot be shared with write access - please share a directory with the file in
it or only share with read access.
                     '''
                })
                return (output_objects, returnvalues.CLIENT_ERROR)

            # We check if abs_path is in vgrid share, but do not worry about
            # private_base or public_base since they are only available to
            # owners, who can always share anyway.

            if vgrid_name is not None and \
                    not vgrid_is_owner(vgrid_name, client_id, configuration):
                # share is inside vgrid share so we must check that user is
                # permitted to create sharelinks there.
                (load_status, settings_dict) = vgrid_settings(vgrid_name,
                                                              configuration,
                                                              recursive=True,
                                                              as_dict=True)
                if not load_status:
                    # Probably owners just never saved settings, use defaults
                    settings_dict = {'vgrid_name': vgrid_name}
                allowed = settings_dict.get('create_sharelink', keyword_owners)
                if allowed != keyword_members:
                    output_objects.append({
                        'object_type': 'error_text',
                        'text': '''The settings
for the %(vgrid_name)s %(vgrid_label)s do not permit you to re-share
%(vgrid_label)s shared folders. Please contact the %(vgrid_name)s owners if you
think you should be allowed to do that.
''' % {
                            'vgrid_name': vgrid_name,
                            'vgrid_label': configuration.site_vgrid_label
                        }
                    })
                    return (output_objects, returnvalues.CLIENT_ERROR)

            access_list = []
            if read_access:
                access_list.append('read')
            if write_access:
                access_list.append('write')

            share_mode = '-'.join((access_list + ['only'])[:2])

            # TODO: more validity checks here

            if share_dict:
                desc = "update"
            else:
                desc = "create"

            # IMPORTANT: always use expanded path
            share_dict.update({
                'path': relative_path,
                'access': access_list,
                'expire': expire,
                'invites': invite_list,
                'single_file': single_file
            })
            attempts = 1
            generate_share_id = False
            if not share_id:
                attempts = 3
                generate_share_id = True
            for i in range(attempts):
                if generate_share_id:
                    share_id = generate_sharelink_id(configuration, share_mode)
                share_dict['share_id'] = share_id
                (save_status,
                 save_msg) = create_share_link(share_dict, client_id,
                                               configuration, share_map)
                if save_status:
                    logger.info('created sharelink: %s' % share_dict)
                    break
                else:
                    # ID Collision?
                    logger.warning('could not create sharelink: %s' % save_msg)
            if save_status and vgrid_name:
                logger.debug("add vgrid sharelink pointer %s" % share_id)
                (add_status,
                 add_msg) = vgrid_add_sharelinks(configuration, vgrid_name,
                                                 [share_dict])
                if not add_status:
                    logger.error(
                        "save vgrid sharelink pointer %s failed: %s " %
                        (share_id, add_msg))
                    return (False, share_map)
        else:
            output_objects.append({
                'object_type': 'error_text',
                'text': 'No such action %s' % action
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

        if not save_status:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Error in %s share link %s: ' % (desc, share_id) +
                'save updated share links failed!'
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

        output_objects.append({
            'object_type':
            'text',
            'text':
            '%sd share link %s on %s .' %
            (desc.title(), share_id, relative_path)
        })
        if action in ['create', 'update']:
            sharelinks = []
            share_item = build_sharelinkitem_object(configuration, share_dict)
            saved_id = share_item['share_id']
            js_name = 'delete%s' % hexlify(saved_id)
            helper = html_post_helper(js_name, '%s.py' % target_op, {
                'share_id': saved_id,
                'action': 'delete',
                csrf_field: csrf_token
            })
            output_objects.append({'object_type': 'html_form', 'text': helper})
            share_item['delsharelink'] = {
                'object_type':
                'link',
                'destination':
                "javascript: confirmDialog(%s, '%s');" %
                (js_name, 'Really remove %s?' % saved_id),
                'class':
                'removelink iconspace',
                'title':
                'Remove share link %s' % saved_id,
                'text':
                ''
            }
            sharelinks.append(share_item)
            output_objects.append({
                'object_type': 'sharelinks',
                'sharelinks': sharelinks
            })
            if action == 'create':
                # NOTE: Leave editsharelink here for use in fileman overlay
                #del share_item['editsharelink']
                output_objects.append({
                    'object_type': 'html_form',
                    'text': '<br />'
                })
                submit_button = '''<span>
            <input type=submit value="Send invitation(s)" />
            </span>'''
                invite_html = invite_share_link_form(configuration, client_id,
                                                     share_dict, 'html',
                                                     submit_button, csrf_token)
                output_objects.append({
                    'object_type': 'html_form',
                    'text': invite_html
                })
    else:
        output_objects.append({
            'object_type': 'error_text',
            'text': 'Invalid share link action: %s' % action
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    output_objects.append({'object_type': 'html_form', 'text': '<br />'})
    output_objects.append({
        'object_type': 'link',
        'destination': 'sharelink.py',
        'text': 'Return to share link overview'
    })

    return (output_objects, returnvalues.OK)
Exemplo n.º 16
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)
    defaults = signature()[1]
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    vgrid_name = accepted['vgrid_name'][-1]

    output_objects.append({'object_type': 'header', 'text'
                          : "Update '%s'" % vgrid_name })

    if not vgrid_is_owner(vgrid_name, client_id, configuration):

        output_objects.append({'object_type': 'error_text', 'text': 
                    'Only owners of %s can administrate it.' % vgrid_name })

        js_name = 'reqvgridowner%s' % hexlify(vgrid_name)
        helper = html_post_helper(js_name, 'sendrequestaction.py',
                                  {'vgrid_name': vgrid_name,
                                   'request_type': 'vgridowner',
                                   'request_text': ''})
        output_objects.append({'object_type': 'html_form', 'text': helper})
        output_objects.append({'object_type': 'link',
                               'destination':
                               "javascript: confirmDialog(%s, '%s', '%s');"\
                               % (js_name, "Request ownership of " + \
                                  vgrid_name + ":<br/>" + \
                                  "\nPlease write a message to the owners (field below).",
                                  'request_text'),
                               'class': 'addadminlink',
                               'title': 'Request ownership of %s' % vgrid_name,
                               'text': 'Apply to become an owner'})

        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.vgrid_home,
                               vgrid_name)) + os.sep
    public_base_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_public_base,
                        vgrid_name)) + os.sep
    public_scm_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_public_base,
                        vgrid_name, '.vgridscm')) + os.sep
    public_tracker_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_public_base,
                        vgrid_name, '.vgridtracker')) + os.sep
    private_base_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_private_base,
                        vgrid_name)) + os.sep
    private_scm_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_private_base,
                        vgrid_name, '.vgridscm')) + os.sep
    private_tracker_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_private_base,
                        vgrid_name, '.vgridtracker')) + os.sep
    private_forum_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_private_base,
                        vgrid_name, '.vgridforum')) + os.sep
    vgrid_files_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_files_home,
                        vgrid_name)) + os.sep
    vgrid_scm_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_files_home,
                        vgrid_name, '.vgridscm')) + os.sep
    vgrid_tracker_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_files_home,
                        vgrid_name, '.vgridtracker')) + os.sep

    output_objects.append({'object_type': 'text', 'text'
                           : 'Updating %s %s components ...' % \
                           (configuration.site_vgrid_label, vgrid_name)})
    
    # Try to create all base directories used for vgrid files

    for path in (base_dir, public_base_dir, private_base_dir, vgrid_files_dir):
        try:
            os.mkdir(path)
        except Exception, exc:
            pass
Exemplo n.º 17
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)
    status = returnvalues.OK
    defaults = signature()[1]
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    show_sandboxes = (accepted['show_sandboxes'][-1] != 'false')

    visible_exes = user_visible_res_exes(configuration, client_id)
    res_map = get_resource_map(configuration)
    anon_map = anon_to_real_res_map(configuration.resource_home)

    # Iterate through resources and show management for each one requested

    res_list = {'object_type': 'resource_list', 'resources': []}
    fields = ['PUBLICNAME', 'NODECOUNT', 'CPUCOUNT', 'MEMORY', 'DISK', 'ARCHITECTURE',
              'SANDBOX', 'RUNTIMEENVIRONMENT']
    # Leave the sorting to jquery tablesorter
    for visible_res_name in visible_exes.keys():
        unique_resource_name = visible_res_name
        if visible_res_name in anon_map.keys():
            unique_resource_name = anon_map[visible_res_name]

        if not show_sandboxes and sandbox_resource(unique_resource_name):
            continue
        res_obj = {'object_type': 'resource', 'name': visible_res_name}

        if client_id in res_map[unique_resource_name][OWNERS]:

            # Admin of resource when owner

            js_name = 'rmresowner%s' % hexlify(unique_resource_name)
            helper = html_post_helper(js_name, 'rmresowner.py',
                                      {'unique_resource_name':
                                       unique_resource_name,
                                       'cert_id': client_id})
            output_objects.append({'object_type': 'html_form', 'text': helper})
            res_obj['resownerlink'] = \
                                    {'object_type': 'link',
                                     'destination':
                                     "javascript: confirmDialog(%s, '%s');"\
                                     % (js_name, 'Really leave %s owners?' % \
                                        unique_resource_name),
                                     'class': 'removelink',
                                     'title': 'Leave %s owners' % unique_resource_name, 
                                     'text': ''}
            res_obj['resdetailslink'] = \
                                    {'object_type': 'link',
                                     'destination':
                                     'resadmin.py?unique_resource_name=%s'\
                                     % unique_resource_name,
                                     'class': 'adminlink',
                                     'title': 'Administrate %s' % unique_resource_name, 
                                     'text': ''}
        else:

            # link to become owner

            js_name = 'reqresowner%s' % hexlify(unique_resource_name)
            helper = html_post_helper(js_name, 'sendrequestaction.py',
                                      {'unique_resource_name':
                                       visible_res_name,
                                       'request_type': 'resourceowner',
                                       'request_text': ''})
            output_objects.append({'object_type': 'html_form', 'text': helper})
            res_obj['resownerlink'] = \
                                    {'object_type': 'link',
                                     'destination':
                                     "javascript: confirmDialog(%s, '%s', '%s');"\
                                     % (js_name, "Request ownership of " + \
                                        visible_res_name + ":<br/>" + \
                                        "\nPlease write a message to the owners (field below).",
                                        'request_text'),
                                     'class': 'addlink',
                                     'title': 'Request ownership of %s' % visible_res_name,
                                     'text': ''}
            
            res_obj['resdetailslink'] = \
                                    {'object_type': 'link',
                                     'destination':
                                     'viewres.py?unique_resource_name=%s'\
                                     % visible_res_name,
                                     'class': 'infolink',
                                     'title': 'View detailed %s specs' % \
                                     visible_res_name, 
                                     'text': ''}
            
        # fields for everyone: public status
        for name in fields:
            res_obj[name] = res_map[unique_resource_name][CONF].get(name, '')
        # Use runtimeenvironment names instead of actual definitions
        res_obj['RUNTIMEENVIRONMENT'] = [i[0] for i in res_obj['RUNTIMEENVIRONMENT']]
        res_list['resources'].append(res_obj)

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'Resource management'

    # jquery support for tablesorter and confirmation on "leave":

    title_entry['style'] = themed_styles(configuration)
    title_entry['javascript'] = '''
<script type="text/javascript" src="/images/js/jquery.js"></script>
<script type="text/javascript" src="/images/js/jquery.tablesorter.js"></script>
<script type="text/javascript" src="/images/js/jquery.tablesorter.pager.js"></script>
<script type="text/javascript" src="/images/js/jquery.tablesorter.widgets.js"></script>
<script type="text/javascript" src="/images/js/jquery-ui.js"></script>
<script type="text/javascript" src="/images/js/jquery.confirm.js"></script>

<script type="text/javascript" >

$(document).ready(function() {

          // init confirmation dialog
          $( "#confirm_dialog" ).dialog(
              // see http://jqueryui.com/docs/dialog/ for options
              { autoOpen: false,
                modal: true, closeOnEscape: true,
                width: 500,
                buttons: {
                   "Cancel": function() { $( "#" + name ).dialog("close"); }
                }
              });

          // table initially sorted by col. 1 (admin), then 0 (name)
          var sortOrder = [[1,0],[0,0]];

          // use image path for sorting if there is any inside
          var imgTitle = function(contents) {
              var key = $(contents).find("a").attr("class");
              if (key == null) {
                  key = $(contents).html();
              }
              return key;
          }
          
          $("#resourcetable").tablesorter({widgets: ["zebra", "saveSort"],
                                        sortList:sortOrder,
                                        textExtraction: imgTitle
                                        })
                             .tablesorterPager({ container: $("#pager"),
                                        size: %s
                                        });
     }
);
</script>
''' % default_pager_entries

    output_objects.append({'object_type': 'html_form',
                           'text':'''
 <div id="confirm_dialog" title="Confirm" style="background:#fff;">
  <div id="confirm_text"><!-- filled by js --></div>
   <textarea cols="40" rows="4" id="confirm_input" style="display:none;"></textarea>
 </div>
'''                       })

    output_objects.append({'object_type': 'header', 'text': 'Available Resources'
                          })

    output_objects.append({'object_type': 'sectionheader', 'text'
                          : 'Resources available on this server'})
    output_objects.append({'object_type': 'text', 'text'
                          : '''
All available resources are listed below with overall hardware specifications. Any resources that you own will have a administration icon that you can click to open resource management.
'''
                       })

    output_objects.append({'object_type': 'table_pager', 'entry_name': 'resources',
                           'default_entries': default_pager_entries})
    output_objects.append(res_list)

    if configuration.site_enable_sandboxes:
        if show_sandboxes:
            output_objects.append({'object_type': 'link',
                                   'destination': '?show_sandboxes=false',
                                   'class': 'removeitemlink',
                                   'title': 'Hide sandbox resources', 
                                   'text': 'Exclude sandbox resources',
                                   })

        else:
            output_objects.append({'object_type': 'link',
                                   'destination': '?show_sandboxes=true',
                                   'class': 'additemlink',
                                   'title': 'Show sandbox resources', 
                                   'text': 'Include sandbox resources',
                                   })

    output_objects.append({'object_type': 'sectionheader', 'text'
                          : 'Resource Status'})
    output_objects.append({'object_type': 'text',
                           'text': '''
Live resource status is available in the resource monitor page with all
%s/resources you can access
''' % configuration.site_vgrid_label})
    output_objects.append({'object_type': 'link',
                           'destination': 'showvgridmonitor.py?vgrid_name=ALL',
                           'class': 'monitorlink',
                           'title': 'Show monitor with all resources you can access', 
                           'text': 'Global resource monitor',
                           })

    output_objects.append({'object_type': 'sectionheader', 'text': 'Additional Resources'
                          })
    output_objects.append({'object_type': 'text',
                           'text': 'You can sign up spare or dedicated resources to the grid below.'
                           })
    output_objects.append({'object_type': 'link',
                           'destination' : 'resedit.py',
                           'class': 'addlink',
                           'title': 'Show sandbox resources',                            
                           'text': 'Create a new %s resource' % \
                           configuration.short_title, 
                           })
    output_objects.append({'object_type': 'sectionheader', 'text': ''})

    if configuration.site_enable_sandboxes:
        output_objects.append({'object_type': 'link',
                               'destination': 'ssslogin.py',
                               'class': 'adminlink',
                               'title': 'Administrate and monitor your sandbox resources',
                               'text': 'Administrate %s sandbox resources' % \
                               configuration.short_title,
                               })
        output_objects.append({'object_type': 'sectionheader', 'text': ''})
        output_objects.append({'object_type': 'link',
                               'destination': 'oneclick.py',
                               'class': 'sandboxlink',
                               'title': 'Run a One-click resource in your browser', 
                               'text': 'Use this computer as One-click %s resource' % \
                               configuration.short_title,
                               })

    return (output_objects, status)
Exemplo n.º 18
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)
    status = returnvalues.OK
    defaults = signature()[1]
    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'Resource management'
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
    )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    show_sandboxes = (accepted['show_sandboxes'][-1] != 'false')
    operation = accepted['operation'][-1]
    caching = (accepted['caching'][-1].lower() in ('true', 'yes'))

    if not configuration.site_enable_resources:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''Resources are not enabled on this system'''
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)

    if not operation in allowed_operations:
        output_objects.append({
            'object_type':
            'text',
            'text':
            '''Operation must be one of %s.''' % ', '.join(allowed_operations)
        })
        return (output_objects, returnvalues.OK)

    logger.info("%s %s begin for %s" % (op_name, operation, client_id))
    pending_updates = False
    if operation in show_operations:

        # jquery support for tablesorter and confirmation on delete
        # table initially sorted by col. 1 (admin), then 0 (name)

        # NOTE: We distinguish between caching on page load and forced refresh
        refresh_call = 'ajax_resman(%s)'
        table_spec = {
            'table_id': 'resourcetable',
            'sort_order': '[[1,0],[0,0]]',
            'refresh_call': refresh_call % 'false'
        }
        (add_import, add_init,
         add_ready) = man_base_js(configuration, [table_spec])
        if operation == "show":
            add_ready += '%s;' % refresh_call % 'true'
        title_entry['script']['advanced'] += add_import
        title_entry['script']['init'] += add_init
        title_entry['script']['ready'] += add_ready
        output_objects.append({
            'object_type': 'html_form',
            'text': man_base_html(configuration)
        })

        output_objects.append({
            'object_type': 'header',
            'text': 'Available Resources'
        })

        output_objects.append({
            'object_type': 'sectionheader',
            'text': 'Resources available on this server'
        })
        output_objects.append({
            'object_type':
            'text',
            'text':
            '''
All available resources are listed below with overall hardware specifications.
Any resources that you own will have a administration icon that you can click
to open resource management.
'''
        })

        # Helper forms for requests and removes

        form_method = 'post'
        csrf_limit = get_csrf_limit(configuration)
        target_op = 'sendrequestaction'
        csrf_token = make_csrf_token(configuration, form_method, target_op,
                                     client_id, csrf_limit)
        helper = html_post_helper(
            'reqresowner', '%s.py' % target_op, {
                'unique_resource_name': '__DYNAMIC__',
                'request_type': 'resourceowner',
                'request_text': '',
                csrf_field: csrf_token
            })
        output_objects.append({'object_type': 'html_form', 'text': helper})
        target_op = 'rmresowner'
        csrf_token = make_csrf_token(configuration, form_method, target_op,
                                     client_id, csrf_limit)
        helper = html_post_helper(
            'rmresowner', '%s.py' % target_op, {
                'unique_resource_name': '__DYNAMIC__',
                'cert_id': client_id,
                csrf_field: csrf_token
            })
        output_objects.append({'object_type': 'html_form', 'text': helper})

        output_objects.append({
            'object_type': 'table_pager',
            'entry_name': 'resources',
            'default_entries': default_pager_entries
        })

    resources = []
    if operation in list_operations:
        logger.info("get vgrid and resource map with caching %s" % caching)
        visible_res_confs = user_visible_res_confs(configuration, client_id,
                                                   caching)
        res_map = get_resource_map(configuration, caching)
        anon_map = anon_to_real_res_map(configuration.resource_home)

        if caching:
            modified_resources, _ = check_resources_modified(configuration)
            modified_vgrids, _ = check_vgrids_modified(configuration)
            if modified_resources:
                logger.info("pending resource cache updates: %s" %
                            modified_resources)
                pending_updates = True
            elif modified_vgrids:
                logger.info("pending vgrid cache updates: %s" %
                            modified_vgrids)
                pending_updates = True
            else:
                logger.info("no pending cache updates")

        # Iterate through resources and show management for each one requested

        fields = [
            'PUBLICNAME', 'NODECOUNT', 'CPUCOUNT', 'MEMORY', 'DISK',
            'ARCHITECTURE', 'SANDBOX', 'RUNTIMEENVIRONMENT'
        ]

        # NOTE: only resources that user is allowed to access are listed.
        #       Resource with neither exes nor stores are not shown to anyone
        #       but the owners. Similarly resources are not shown if all
        #       resource units solely participate in VGrids, which the user
        #       can't access.
        for visible_res_name in visible_res_confs.keys():
            unique_resource_name = visible_res_name
            if visible_res_name in anon_map.keys():
                unique_resource_name = anon_map[visible_res_name]

            if not show_sandboxes and sandbox_resource(unique_resource_name):
                continue
            res_obj = {'object_type': 'resource', 'name': visible_res_name}

            if client_id in res_map[unique_resource_name][OWNERS]:

                # Admin of resource when owner

                res_obj['resownerlink'] = {
                    'object_type':
                    'link',
                    'destination':
                    "javascript: confirmDialog(%s, '%s', %s, %s);" %
                    ('rmresowner', 'Really leave %s owners?' %
                     unique_resource_name, 'undefined',
                     "{unique_resource_name: '%s'}" % unique_resource_name),
                    'class':
                    'removelink iconspace',
                    'title':
                    'Leave %s owners' % unique_resource_name,
                    'text':
                    ''
                }
                res_obj['resdetailslink'] = {
                    'object_type': 'link',
                    'destination': 'resadmin.py?unique_resource_name=%s' %
                    unique_resource_name,
                    'class': 'adminlink iconspace',
                    'title': 'Administrate %s' % unique_resource_name,
                    'text': ''
                }
            else:

                # link to become owner

                res_obj['resownerlink'] = {
                    'object_type':
                    'link',
                    'destination':
                    "javascript: confirmDialog(%s, '%s', '%s', %s);" %
                    ('reqresowner',
                     "Request ownership of " + visible_res_name + ":<br/>" +
                     "\nPlease write a message to the owners (field below).",
                     'request_text',
                     "{unique_resource_name: '%s'}" % visible_res_name),
                    'class':
                    'addlink iconspace',
                    'title':
                    'Request ownership of %s' % visible_res_name,
                    'text':
                    ''
                }

                res_obj['resdetailslink'] = {
                    'object_type': 'link',
                    'destination':
                    'viewres.py?unique_resource_name=%s' % visible_res_name,
                    'class': 'infolink iconspace',
                    'title': 'View detailed %s specs' % visible_res_name,
                    'text': ''
                }

            # fields for everyone: public status
            for name in fields:
                res_obj[name] = res_map[unique_resource_name][CONF].get(
                    name, '')
            # Use runtimeenvironment names instead of actual definitions
            res_obj['RUNTIMEENVIRONMENT'] = [
                i[0] for i in res_obj['RUNTIMEENVIRONMENT']
            ]
            res_obj['RUNTIMEENVIRONMENT'].sort()
            resources.append(res_obj)

    if operation == "show":
        # insert dummy placeholder to build table
        res_obj = {'object_type': 'resource', 'name': ''}
        resources.append(res_obj)

    output_objects.append({
        'object_type': 'resource_list',
        'pending_updates': pending_updates,
        'resources': resources
    })

    if operation in show_operations:
        if configuration.site_enable_sandboxes:
            if show_sandboxes:
                output_objects.append({
                    'object_type': 'link',
                    'destination': '?show_sandboxes=false',
                    'class': 'removeitemlink iconspace',
                    'title': 'Hide sandbox resources',
                    'text': 'Exclude sandbox resources',
                })

            else:
                output_objects.append({
                    'object_type': 'link',
                    'destination': '?show_sandboxes=true',
                    'class': 'additemlink iconspace',
                    'title': 'Show sandbox resources',
                    'text': 'Include sandbox resources',
                })

        output_objects.append({
            'object_type': 'sectionheader',
            'text': 'Resource Status'
        })
        output_objects.append({
            'object_type':
            'text',
            'text':
            '''
Live resource status is available in the resource monitor page with all
%s/resources you can access
''' % configuration.site_vgrid_label
        })
        output_objects.append({
            'object_type': 'link',
            'destination': 'showvgridmonitor.py?vgrid_name=ALL',
            'class': 'monitorlink iconspace',
            'title': 'Show monitor with all resources you can access',
            'text': 'Global resource monitor',
        })

        output_objects.append({
            'object_type': 'sectionheader',
            'text': 'Additional Resources'
        })
        output_objects.append({
            'object_type':
            'text',
            'text':
            'You can sign up spare or dedicated resources to the grid below.'
        })
        output_objects.append({
            'object_type':
            'link',
            'destination':
            'resedit.py',
            'class':
            'addlink iconspace',
            'title':
            'Show sandbox resources',
            'text':
            'Create a new %s resource' % configuration.short_title,
        })
        output_objects.append({'object_type': 'sectionheader', 'text': ''})

        if configuration.site_enable_sandboxes:
            output_objects.append({
                'object_type':
                'link',
                'destination':
                'ssslogin.py',
                'class':
                'adminlink iconspace',
                'title':
                'Administrate and monitor your sandbox resources',
                'text':
                'Administrate %s sandbox resources' % configuration.short_title
            })
            output_objects.append({'object_type': 'sectionheader', 'text': ''})
            output_objects.append({
                'object_type':
                'link',
                'destination':
                'oneclick.py',
                'class':
                'sandboxlink iconspace',
                'title':
                'Run a One-click resource in your browser',
                'text':
                'Use this computer as One-click %s resource' %
                configuration.short_title
            })

    logger.info("%s %s end for %s" % (op_name, operation, client_id))
    return (output_objects, status)
Exemplo n.º 19
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)

    output_objects.append({
        'object_type': 'header',
        'text': 'Virtual Machines'
    })
    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)

    machine_name = accepted['machine_name'][-1].strip()
    memory = int(accepted['memory'][-1])
    disk = int(accepted['disk'][-1])
    vgrid = [name.strip() for name in accepted['vgrid']]
    architecture = accepted['architecture'][-1].strip()
    cpu_count = int(accepted['cpu_count'][-1])
    cpu_time = int(accepted['cpu_time'][-1])
    op_sys = accepted['os'][-1].strip()
    flavor = accepted['flavor'][-1].strip()
    hypervisor_re = accepted['hypervisor_re'][-1].strip()
    sys_re = accepted['sys_re'][-1].strip()
    action = accepted['action'][-1].strip()

    if action in edit_actions and \
        not safe_handler(configuration, 'post', op_name, client_id,
                         get_csrf_limit(configuration), accepted):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''Only accepting
CSRF-filtered POST requests to prevent unintended updates'''
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'Virtual Machines'

    # jquery support for confirmation on delete:
    (add_import, add_init, add_ready) = confirm_js(configuration)

    add_ready += '''
          $(".vm-tabs").tabs();
    '''
    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': confirm_html(configuration)
    })

    if not configuration.site_enable_vmachines:
        output_objects.append({
            'object_type':
            'text',
            'text':
            '''Virtual machines are disabled on this site.
Please contact the site admins %s if you think they should be enabled.
''' % configuration.admin_email
        })
        return (output_objects, returnvalues.OK)

    machine_req = {
        'memory': memory,
        'disk': disk,
        'cpu_count': cpu_count,
        'cpu_time': cpu_time,
        'architecture': architecture,
        'vgrid': vgrid,
        'os': op_sys,
        'flavor': flavor,
        'hypervisor_re': hypervisor_re,
        'sys_re': sys_re
    }

    menu_items = ['vmrequest']

    # Html fragments

    submenu = render_menu(configuration,
                          menu_class='navsubmenu',
                          base_menu=[],
                          user_menu=menu_items)

    welcome_text = 'Welcome to your %s virtual machine management!' % \
                   configuration.short_title
    desc_text = '''On this page you can:
<ul>
    <li>Request Virtual Machines, by clicking on the button above</li>
    <li>See your virtual machines in the list below.</li>
    <li>Start, and connect to your Virtual Machine by clicking on it.</li>
    <li>Edit or delete your Virtual Machine from the Advanced tab.</li>
</ul>
'''

    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': 'html_form', 'text': submenu})
    output_objects.append({
        'object_type': 'html_form',
        'text': '<p>&nbsp;</p>'
    })
    output_objects.append({
        'object_type': 'sectionheader',
        'text': welcome_text
    })
    output_objects.append({'object_type': 'html_form', 'text': desc_text})

    user_vms = vms.vms_list(client_id, configuration)
    if action == 'create':
        if not configuration.site_enable_vmachines:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                "Virtual machines are disabled on this server"
            })
            status = returnvalues.CLIENT_ERROR
            return (output_objects, status)
        if not machine_name:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                "requested build without machine name"
            })
            status = returnvalues.CLIENT_ERROR
            return (output_objects, status)
        elif machine_name in [vm["name"] for vm in user_vms]:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                "requested machine name '%s' already exists!" % machine_name
            })
            status = returnvalues.CLIENT_ERROR
            return (output_objects, status)
        elif not flavor in vms.available_flavor_list(configuration):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                "requested pre-built flavor not available: %s" % flavor
            })
            status = returnvalues.CLIENT_ERROR
            return (output_objects, status)
        elif not hypervisor_re in \
                vms.available_hypervisor_re_list(configuration):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                "requested hypervisor runtime env not available: %s" %
                hypervisor_re
            })
        elif not sys_re in vms.available_sys_re_list(configuration):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                "requested system pack runtime env not available: %s" % sys_re
            })
            status = returnvalues.CLIENT_ERROR
            return (output_objects, status)

        # TODO: support custom build of machine using shared/vmbuilder.py

        # request for existing pre-built machine

        logger.debug("create new vm: %s" % machine_req)
        (create_status, create_msg) = vms.create_vm(client_id, configuration,
                                                    machine_name, machine_req)
        if not create_status:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                "requested virtual machine could not be created: %s" %
                create_msg
            })
            status = returnvalues.SYSTEM_ERROR
            return (output_objects, status)

    (action_status, action_msg, job_id) = (True, '', None)
    if action in ['start', 'stop', 'edit', 'delete']:
        if not configuration.site_enable_vmachines:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                "Virtual machines are disabled on this server"
            })
            status = returnvalues.CLIENT_ERROR
            return (output_objects, status)
    if action == 'start':
        machine = {}
        for entry in user_vms:
            if machine_name == entry['name']:
                for name in machine_req.keys():
                    if isinstance(entry[name], basestring) and \
                            entry[name].isdigit():
                        machine[name] = int(entry[name])
                    else:
                        machine[name] = entry[name]
                break
        (action_status, action_msg, job_id) = \
            vms.enqueue_vm(client_id, configuration, machine_name,
                           machine)
    elif action == 'edit':
        if not machine_name in [vm['name'] for vm in user_vms]:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                "No such virtual machine: %s" % machine_name
            })
            status = returnvalues.CLIENT_ERROR
            return (output_objects, status)
        (action_status, action_msg) = \
            vms.edit_vm(client_id, configuration, machine_name,
                        machine_req)
    elif action == 'delete':
        if not machine_name in [vm['name'] for vm in user_vms]:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                "No such virtual machine: %s" % machine_name
            })
            status = returnvalues.CLIENT_ERROR
            return (output_objects, status)
        (action_status, action_msg) = \
            vms.delete_vm(client_id, configuration, machine_name)
    elif action == 'stop':

        # TODO: manage stop - use live I/O to create vmname.stop in job dir

        pass

    if not action_status:
        output_objects.append({
            'object_type': 'error_text',
            'text': action_msg
        })

    # List the machines here

    output_objects.append({
        'object_type': 'sectionheader',
        'text': 'Your machines:'
    })

    # Grab the vms available for the user

    machines = vms.vms_list(client_id, configuration)

    # Visual representation mapping of the machine state

    machine_states = {
        'EXECUTING': 'vm_running.jpg',
        'CANCELED': 'vm_off.jpg',
        'FAILED': 'vm_off.jpg',
        'FINISHED': 'vm_off.jpg',
        'UNKNOWN': 'vm_off.jpg',
        'QUEUED': 'vm_booting.jpg',
        'PARSE': 'vm_booting.jpg',
    }

    # Empirical upper bound on boot time in seconds used to decide between
    # desktop init and ready states

    boot_secs = 130

    # CANCELED/FAILED/FINISHED -> Powered Off
    # QUEUED -> Booting

    if len(machines) > 0:

        form_method = 'post'
        csrf_limit = get_csrf_limit(configuration)
        fill_helpers = {
            'form_method': form_method,
            'csrf_field': csrf_field,
            'csrf_limit': csrf_limit
        }
        target_op = 'vmachines'
        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})
        # Create a pretty list with start/edit/stop/connect links

        pretty_machines = \
            '<table style="border: 0; background: none;"><tr>'
        side_by_side = 3  # How many machines should be shown in a row?

        col = 0
        for machine in machines:

            # Machines on a row

            if col % side_by_side == 0:
                pretty_machines += '</tr><tr>'
            col += 1

            # Html format machine specifications in a fieldset

            password = '******'
            exec_time = 0
            if machine['job_id'] != 'UNKNOWN' and \
                    machine['status'] == 'EXECUTING':

                # TODO: improve on this time selection...
                # ... in distributed there is no global clock!

                exec_time = time.time() - 3600 \
                    - time.mktime(machine['execution_time'])
                password = vms.vnc_jobid(machine['job_id'])

            machine_specs = {}
            machine_specs.update(machine)
            machine_specs['password'] = password
            show_specs = """<fieldset>
<legend>VM Specs:</legend><ul class="no-bullets">
<li><input type="text" readonly value="%(os)s"> base system</li>
<li><input type="text" readonly value="%(flavor)s"> software flavor</li>
<li><input type="text" readonly value="%(memory)s"> MB memory</li>
<li><input type="text" readonly value="%(disk)s"> GB disk</li>
<li><input type="text" readonly value="%(cpu_count)s"> CPU's</li>
<li><input type="text" readonly value="%(vm_arch)s"> architecture</li>
"""
            if password != 'UNKNOWN':
                show_specs += """            
<li><input type="text" readonly value="%(password)s"> as VNC password</li>
"""
            show_specs += """            
</form></ul></fieldset>"""
            edit_specs = """<fieldset>
<legend>Edit VM Specs:</legend><ul class="no-bullets">
<form method="%(form_method)s" action="%(target_op)s.py">
<input type="hidden" name="%(csrf_field)s" value="%(csrf_token)s" />
<input type="hidden" name="action" value="edit">
""" % fill_helpers
            edit_specs += """
<input type="hidden" name="machine_name" value="%(name)s">
<input type="hidden" name="output_format" value="html">

<li><input type="text" readonly name="os" value="%(os)s"> base system</li>
<li><input type="text" readonly name="flavor" value="%(flavor)s"> software flavor</li>
<li><input type="text" readonly name="hypervisor_re" value="%(hypervisor_re)s"> hypervisor runtime env</li>
<li><input type="text" readonly name="sys_re" value="%(sys_re)s"> image pack runtime env</li>
<li><input type="text" name="memory" value="%(memory)s"> MB memory</li>
<li><input type="text" name="disk" value="%(disk)s"> GB disk</li>
<li><input type="text" name="cpu_count" value="%(cpu_count)s"> CPU's</li>
<li><select name="architecture">
"""
            for arch in [''] + configuration.architectures:
                select = ''
                if arch == machine_specs['architecture']:
                    select = 'selected'
                edit_specs += "<option %s value='%s'>%s</option>" % (
                    select, arch, arch)
            edit_specs += """</select> resource architecture
<li><input type="text" name="cpu_time" value="%(cpu_time)s"> s time slot</li>
<li><select name="vgrid" multiple>"""
            for vgrid_name in [any_vgrid] + \
                    user_vgrid_access(configuration, client_id):
                select = ''
                if vgrid_name in machine_specs['vgrid']:
                    select = 'selected'
                edit_specs += "<option %s>%s</option>" % (select, vgrid_name)
            edit_specs += """</select> %s(s)</li>""" % \
                          configuration.site_vgrid_label
            if password != 'UNKNOWN':
                edit_specs += """
<li><input type="text" readonly value="%(password)s"> as VNC password</li>
"""
            edit_specs += """
<input class="styled_button" type="submit" value="Save Changes">
</form>"""
            js_name = 'deletevm%s' % hexlify("%(name)s" % machine_specs)
            helper = html_post_helper(
                js_name, '%s.py' % target_op, {
                    'machine_name': machine_specs['name'],
                    'action': 'delete',
                    csrf_field: csrf_token
                })
            edit_specs += helper
            edit_specs += """<input class="styled_button" type="submit"
value="Delete Machine" onClick="javascript: confirmDialog(%s, '%s');" >
""" % (js_name, "Really permanently delete %(name)s VM?" % machine_specs)
            edit_specs += """</ul></fieldset>"""
            if machine['status'] == 'EXECUTING' and exec_time > boot_secs:
                machine_image = '<img src="/images/vms/' \
                    + machine_states[machine['status']] + '">'
            elif machine['status'] == 'EXECUTING' and exec_time < boot_secs:
                machine_image = \
                    '<img src="/images/vms/vm_desktop_loading.jpg' \
                    + '">'
            else:
                machine_image = '<img src="/images/vms/' \
                    + machine_states[machine['status']] + '">'
            machine_link = vms.machine_link(machine_image, machine['job_id'],
                                            machine['name'], machine['uuid'],
                                            machine['status'], machine_req)

            # Smack all the html together

            fill_dict = {}
            fill_dict.update(machine)
            fill_dict['link'] = machine_link
            fill_dict['show_specs'] = show_specs % machine_specs
            fill_dict['edit_specs'] = edit_specs % machine_specs
            pretty_machines += '''
<td style="vertical-align: top;">
<fieldset><legend>%(name)s</legend>
<div id="%(name)s-tabs" class="vm-tabs">
<ul>
<li><a href="#%(name)s-overview">Overview</a></li>
<li><a href="#%(name)s-edit">Advanced</a></li>
</ul>
<div id="%(name)s-overview">
<p>%(link)s</p>
%(show_specs)s
</div>
<div id="%(name)s-edit">
%(edit_specs)s
</div>
</div>
</fieldset>
</td>''' % fill_dict

        pretty_machines += '</tr></table>'

        output_objects.append({
            'object_type': 'html_form',
            'text': pretty_machines
        })
    else:
        output_objects.append({
            'object_type':
            'text',
            'text':
            "You don't have any virtual machines! "
            "Click 'Request Virtual Machine' to become a proud owner :)"
        })

    return (output_objects, status)
Exemplo n.º 20
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'] = 'People'
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
    )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    operation = accepted['operation'][-1]
    caching = (accepted['caching'][-1].lower() in ('true', 'yes'))

    if not operation in allowed_operations:
        output_objects.append({'object_type': 'text', 'text':
                               '''Operation must be one of %s.''' %
                               ', '.join(allowed_operations)})
        return (output_objects, returnvalues.OK)

    logger.info("%s %s begin for %s" % (op_name, operation, client_id))
    pending_updates = False
    if operation in show_operations:

        # jquery support for tablesorter and confirmation on "send"
        # table initially sorted by 0 (name)

        # NOTE: We distinguish between caching on page load and forced refresh
        refresh_helper = 'ajax_people(%s, %%s)'
        refresh_call = refresh_helper % configuration.notify_protocols
        table_spec = {'table_id': 'usertable', 'sort_order': '[[0,0]]',
                      'refresh_call': refresh_call % 'false'}
        (add_import, add_init, add_ready) = man_base_js(configuration,
                                                        [table_spec],
                                                        {'width': 640})
        if operation == "show":
            add_ready += '%s;' % (refresh_call % 'true')
        title_entry['script']['advanced'] += add_import
        title_entry['script']['init'] += add_init
        title_entry['script']['ready'] += add_ready

        output_objects.append({'object_type': 'html_form',
                               'text': man_base_html(configuration)})

        output_objects.append({'object_type': 'header', 'text': 'People'})

        output_objects.append(
            {'object_type': 'text', 'text':
             'View and communicate with other users.'
             })

        output_objects.append(
            {'object_type': 'sectionheader', 'text': 'All users'})

        # Helper form for sends

        form_method = 'post'
        csrf_limit = get_csrf_limit(configuration)
        target_op = 'sendrequestaction'
        csrf_token = make_csrf_token(configuration, form_method, target_op,
                                     client_id, csrf_limit)
        helper = html_post_helper('sendmsg', '%s.py' % target_op,
                                  {'cert_id': '__DYNAMIC__',
                                   'protocol': '__DYNAMIC__',
                                   'request_type': 'plain',
                                   'request_text': '',
                                   csrf_field: csrf_token})
        output_objects.append({'object_type': 'html_form', 'text':
                               helper})

        output_objects.append({'object_type': 'table_pager', 'entry_name':
                               'people', 'default_entries':
                               default_pager_entries})

    users = []
    if operation in list_operations:
        logger.info("get vgrid and user map with caching %s" % caching)
        visible_user = user_visible_user_confs(configuration, client_id,
                                               caching)
        vgrid_access = user_vgrid_access(configuration, client_id,
                                         caching=caching)
        anon_map = anon_to_real_user_map(configuration)
        if not visible_user:
            output_objects.append(
                {'object_type': 'error_text', 'text': 'no users found!'})
            return (output_objects, returnvalues.SYSTEM_ERROR)

        if caching:
            modified_users, _ = check_users_modified(configuration)
            modified_vgrids, _ = check_vgrids_modified(configuration)
            if modified_users:
                logger.info("pending user cache updates: %s" % modified_users)
                pending_updates = True
            elif modified_vgrids:
                logger.info("pending vgrid cache updates: %s" %
                            modified_vgrids)
                pending_updates = True
            else:
                logger.info("no pending cache updates")

        for (visible_user_id, user_dict) in visible_user.items():
            user_id = visible_user_id
            if visible_user_id in anon_map.keys():
                # Maintain user anonymity
                pretty_id = 'Anonymous user with unique ID %s' % visible_user_id
                user_id = anon_map[visible_user_id]
            else:
                # Show user-friendly version of user ID
                hide_email = user_dict.get(CONF, {}).get('HIDE_EMAIL_ADDRESS',
                                                         True)
                pretty_id = pretty_format_user(user_id, hide_email)
            user_obj = {'object_type': 'user', 'name': visible_user_id,
                        'pretty_id': pretty_id}
            user_obj.update(user_dict)
            # NOTE: datetime is not json-serializable so we force to string
            created = user_obj.get(CONF, {}).get('CREATED_TIMESTAMP', '')
            if created:
                user_obj[CONF]['CREATED_TIMESTAMP'] = str(created)
            user_obj['userdetailslink'] = \
                {'object_type': 'link',
                 'destination':
                 'viewuser.py?cert_id=%s'
                 % quote(visible_user_id),
                 'class': 'infolink iconspace',
                 'title': 'View details for %s' %
                 visible_user_id,
                 'text': ''}
            vgrids_allow_email = user_dict[CONF].get('VGRIDS_ALLOW_EMAIL', [])
            vgrids_allow_im = user_dict[CONF].get('VGRIDS_ALLOW_IM', [])
            if any_vgrid in vgrids_allow_email:
                email_vgrids = vgrid_access
            else:
                email_vgrids = set(
                    vgrids_allow_email).intersection(vgrid_access)
            if any_vgrid in vgrids_allow_im:
                im_vgrids = vgrid_access
            else:
                im_vgrids = set(vgrids_allow_im).intersection(vgrid_access)
            for proto in configuration.notify_protocols:
                if not email_vgrids and proto == 'email':
                    continue
                if not im_vgrids and proto != 'email':
                    continue
                if user_obj[CONF].get(proto.upper(), None):
                    link = 'send%slink' % proto
                    user_obj[link] = {
                        'object_type': 'link',
                        'destination':
                        "javascript: confirmDialog(%s, '%s', '%s', %s);"
                        % ('sendmsg', 'Really send %s message to %s?'
                           % (proto, visible_user_id),
                           'request_text',
                           "{cert_id: '%s', 'protocol': '%s'}" %
                           (visible_user_id, proto)),
                        'class': "%s iconspace" % link,
                        'title': 'Send %s message to %s' %
                        (proto, visible_user_id),
                        'text': ''}
            logger.debug("append user %s" % user_obj)
            users.append(user_obj)

    if operation == "show":
        # insert dummy placeholder to build table
        user_obj = {'object_type': 'user', 'name': ''}
        users.append(user_obj)

    output_objects.append({'object_type': 'user_list',
                           'pending_updates': pending_updates,
                           'users': users})

    logger.info("%s %s end for %s" % (op_name, operation, client_id))
    return (output_objects, returnvalues.OK)
Exemplo n.º 21
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)
    defaults = signature()[1]
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
    )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    action = accepted['action'][-1]
    transfer_id = accepted['transfer_id'][-1]
    protocol = accepted['protocol'][-1]
    fqdn = accepted['fqdn'][-1]
    port = accepted['port'][-1]
    src_list = accepted['transfer_src']
    dst = accepted['transfer_dst'][-1]
    username = accepted['username'][-1]
    password = accepted['transfer_pw'][-1]
    key_id = accepted['key_id'][-1]
    # Skip empty exclude entries as they break backend calls
    exclude_list = [i for i in accepted['exclude'] if i]
    notify = accepted['notify'][-1]
    compress = accepted['compress'][-1]
    flags = accepted['flags']

    anon_checked, pw_checked, key_checked = '', '', ''
    if username:
        if key_id:
            key_checked = 'checked'
            init_login = "******"
        else:
            pw_checked = 'checked'
            init_login = "******"
    else:
        anon_checked = 'checked'
        init_login = "******"
    use_compress = False
    if compress.lower() in ("true", "1", "yes", "on"):
        use_compress = True

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'Background Data Transfers'

    # jquery support for tablesorter and confirmation on delete/redo:
    # datatransfer and key tables initially sorted by 0 (id) */

    datatransfer_spec = {
        'table_id': 'datatransferstable',
        'pager_id': 'datatransfers_pager',
        'sort_order': '[[0,0]]'
    }
    transferkey_spec = {
        'table_id': 'transferkeystable',
        'pager_id': 'transferkeys_pager',
        'sort_order': '[[0,0]]'
    }
    (add_import, add_init,
     add_ready) = man_base_js(configuration,
                              [datatransfer_spec, transferkey_spec])
    add_init += '''
    var fields = 0;
    var max_fields = 20;
    var src_input = "<label for=\'transfer_src\'>Source path(s)</label>";
    src_input += "<input id=\'src_FIELD\' type=text size=60 name=transfer_src value=\'PATH\' title=\'relative source path: local for exports and remote for imports\' />";
    src_input += "<input id=\'src_file_FIELD\' type=radio onclick=\'setSrcDir(FIELD, false);\' checked />Source file";
    src_input += "<input id=\'src_dir_FIELD\' type=radio onclick=\'setSrcDir(FIELD, true);\' />Source directory (recursive)";
    src_input += "<br />";
    var exclude_input = "<label for=\'exclude\'>Exclude path(s)</label>";
    exclude_input += "<input type=text size=60 name=exclude value=\'PATH\' title=\'relative path or regular expression to exclude\' />";
    exclude_input += "<br />";
    function addSource(path, is_dir) {
        if (path === undefined) {
            path = "";
        }
        if (is_dir === undefined) {
            is_dir = false;
        }
        if (fields < max_fields) {
            $("#srcfields").append(src_input.replace(/FIELD/g, fields).replace(/PATH/g, path));
            setSrcDir(fields, is_dir);
            fields += 1;
        } else {
            alert("Maximum " + max_fields + " source fields allowed!");
        }
    }
    function addExclude(path) {
        if (path === undefined) {
            path = "";
        }
        $("#excludefields").append(exclude_input.replace(/PATH/g, path));
    }
    function setDir(target, field_no, is_dir) {
        var id_prefix = "#"+target+"_";
        var input_id = id_prefix+field_no;
        var file_id = id_prefix+"file_"+field_no;
        var dir_id = id_prefix+"dir_"+field_no;
        var value = $(input_id).val();
        $(file_id).removeAttr("checked");
        $(dir_id).removeAttr("checked");
        if (is_dir) {
            $(dir_id).prop("checked", "checked");
            if(value.substr(-1) != "/") {
                value += "/";
            }
        } else {
            $(file_id).prop("checked", "checked");
            if(value.substr(-1) == "/") {
                value = value.substr(0, value.length - 1);
            }
        }
        $(input_id).val(value);
        return false;
    }
    function setSrcDir(field_no, is_dir) {
        return setDir("src", field_no, is_dir);
    }
    function setDstDir(field_no, is_dir) {
        return setDir("dst", field_no, is_dir);
    }
    function refreshSrcDir(field_no) {
        var dir_id = "#src_dir_"+field_no;
        var is_dir = $(dir_id).prop("checked");
        return setSrcDir(field_no, is_dir);
    }
    function refreshDstDir(field_no) {
        var dir_id = "#dst_dir_"+field_no;
        var is_dir = $(dir_id).prop("checked");
        return setDstDir(field_no, is_dir);
    }
    function setDefaultPort() {
        port_map = {"http": 80, "https": 443, "sftp": 22, "scp": 22, "ftp": 21,
                    "ftps": 21, "webdav": 80, "webdavs": 443, "rsyncssh": 22,
                    "rsyncd": 873};
        var protocol = $("#protocol_select").val();
        var port = port_map[protocol]; 
        if (port != undefined) {
            $("#port_input").val(port);
        } else {
            alert("no default port provided for "+protocol);
        }
    }
    function beforeSubmit() {
        for(var i=0; i < fields; i++) {
            refreshSrcDir(i);
        }
        refreshDstDir(0);
        // Proceed with submit
        return true;
    }
    function doSubmit() {
        $("#submit-request-transfer").click();
    }
    function enableLogin(method) {
        $("#anonymous_choice").removeAttr("checked");
        $("#userpassword_choice").removeAttr("checked");
        $("#userkey_choice").removeAttr("checked");
        $("#username").prop("disabled", false);
        $("#password").prop("disabled", true);
        $("#key").prop("disabled", true);
        $("#login_fields").show();
        $("#password_entry").hide();
        $("#key_entry").hide();
        
        if (method == "password") {
            $("#userpassword_choice").prop("checked", "checked");
            $("#password").prop("disabled", false);
            $("#password_entry").show();
        } else if (method == "key") {
            $("#userkey_choice").prop("checked", "checked");
            $("#key").prop("disabled", false);
            $("#key_entry").show();
        } else {
            $("#anonymous_choice").prop("checked", "checked");
            $("#username").prop("disabled", true);
            $("#login_fields").hide();
        }
    }
    '''
    # Mangle ready handling to begin with dynamic init and end with tab init
    pre_ready = '''
        enableLogin("%s");
        ''' % init_login
    for src in src_list or ['']:
        pre_ready += '''
        addSource("%s", %s);
        ''' % (src, ("%s" % src.endswith('/')).lower())
    for exclude in exclude_list or ['']:
        pre_ready += '''
        addExclude("%s");
        ''' % exclude
    add_ready = '''
        %s
        %s
        /* NOTE: requires managers CSS fix for proper tab bar height */      
        $(".datatransfer-tabs").tabs();
        $("#logarea").scrollTop($("#logarea")[0].scrollHeight);
    ''' % (pre_ready, add_ready)
    title_entry['script']['advanced'] += add_import
    title_entry['script']['init'] += add_init
    title_entry['script']['ready'] += add_ready
    output_objects.append({
        'object_type': 'html_form',
        'text': man_base_html(configuration)
    })

    output_objects.append({
        'object_type': 'header',
        'text': 'Manage background data transfers'
    })

    if not configuration.site_enable_transfers:
        output_objects.append({
            'object_type':
            'text',
            'text':
            '''Backgroung data transfers are disabled on
this site.
Please contact the site admins %s if you think they should be enabled.
''' % configuration.admin_email
        })
        return (output_objects, returnvalues.OK)

    logger.info('datatransfer %s from %s' % (action, client_id))

    if not action in valid_actions:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'Invalid action "%s" (supported: %s)' %
            (action, ', '.join(valid_actions))
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    if action in post_actions:
        if not safe_handler(configuration, 'post', op_name, client_id,
                            get_csrf_limit(configuration), accepted):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                '''Only accepting
                CSRF-filtered POST requests to prevent unintended updates'''
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

    (load_status, transfer_map) = load_data_transfers(configuration, client_id)
    if not load_status:
        transfer_map = {}

    restrict_list = []
    for from_fqdn in configuration.site_transfers_from:
        restrict_list += [from_fqdn, socket.gethostbyname(from_fqdn)]
    restrict_str = 'from="%s",no-pty,' % ','.join(restrict_list)
    restrict_str += 'no-port-forwarding,no-agent-forwarding,no-X11-forwarding'
    restrict_template = '''
As usual it is a good security measure to prepend a <em>from</em> restriction
when you know the key will only be used from a single location.<br/>
In this case the keys will only ever be used from %s and will not need much
else, so the public key can be inserted in your authorized_keys file as:
<br/>
<p>
<textarea class="publickey" rows="5" readonly="readonly">%s %%s</textarea>
</p>
''' % (configuration.short_title, restrict_str)

    form_method = 'post'
    csrf_limit = get_csrf_limit(configuration)
    target_op = 'datatransfer'
    csrf_token = make_csrf_token(configuration, form_method, target_op,
                                 client_id, csrf_limit)
    if action in get_actions:
        datatransfers = []
        for (saved_id, transfer_dict) in transfer_map.items():
            transfer_item = build_transferitem_object(configuration,
                                                      transfer_dict)
            transfer_item['status'] = transfer_item.get('status', 'NEW')
            data_url = ''
            # NOTE: we need to urlencode any exotic chars in paths here
            if transfer_item['action'] == 'import':
                enc_path = quote(("%(dst)s" % transfer_item))
                data_url = "fileman.py?path=%s" % enc_path
            elif transfer_item['action'] == 'export':
                enc_paths = [quote(i) for i in transfer_item['src']]
                data_url = "fileman.py?path=" + ';path='.join(enc_paths)
            if data_url:
                transfer_item['viewdatalink'] = {
                    'object_type': 'link',
                    'destination': data_url,
                    'class': 'viewlink iconspace',
                    'title': 'View local component of %s' % saved_id,
                    'text': ''
                }
            transfer_item['viewoutputlink'] = {
                'object_type': 'link',
                'destination':
                "fileman.py?path=transfer_output/%s/" % saved_id,
                'class': 'infolink iconspace',
                'title': 'View status files for %s' % saved_id,
                'text': ''
            }
            # Edit is just a call to self with fillimport set
            args = [('action', 'fill%(action)s' % transfer_dict),
                    ('key_id', '%(key)s' % transfer_dict),
                    ('transfer_dst', '%(dst)s' % transfer_dict)]
            for src in transfer_dict['src']:
                args.append(('transfer_src', src))
            for exclude in transfer_dict.get('exclude', []):
                args.append(('exclude', exclude))
            for field in edit_fields:
                val = transfer_dict.get(field, '')
                args.append((field, val))
            transfer_args = urlencode(args, True)
            transfer_item['edittransferlink'] = {
                'object_type': 'link',
                'destination': "%s.py?%s" % (target_op, transfer_args),
                'class': 'editlink iconspace',
                'title': 'Edit or duplicate transfer %s' % saved_id,
                'text': ''
            }
            js_name = 'delete%s' % hexlify(saved_id)
            helper = html_post_helper(
                js_name, '%s.py' % target_op, {
                    'transfer_id': saved_id,
                    'action': 'deltransfer',
                    csrf_field: csrf_token
                })
            output_objects.append({'object_type': 'html_form', 'text': helper})
            transfer_item['deltransferlink'] = {
                'object_type':
                'link',
                'destination':
                "javascript: confirmDialog(%s, '%s');" %
                (js_name, 'Really remove %s?' % saved_id),
                'class':
                'removelink iconspace',
                'title':
                'Remove %s' % saved_id,
                'text':
                ''
            }
            js_name = 'redo%s' % hexlify(saved_id)
            helper = html_post_helper(
                js_name, '%s.py' % target_op, {
                    'transfer_id': saved_id,
                    'action': 'redotransfer',
                    csrf_field: csrf_token
                })
            output_objects.append({'object_type': 'html_form', 'text': helper})
            transfer_item['redotransferlink'] = {
                'object_type':
                'link',
                'destination':
                "javascript: confirmDialog(%s, '%s');" %
                (js_name, 'Really reschedule %s?' % saved_id),
                'class':
                'refreshlink iconspace',
                'title':
                'Reschedule %s' % saved_id,
                'text':
                ''
            }
            datatransfers.append(transfer_item)
        #logger.debug("found datatransfers: %s" % datatransfers)
        log_path = os.path.join(configuration.user_home,
                                client_id_dir(client_id), "transfer_output",
                                configuration.site_transfer_log)
        show_lines = 40
        log_lines = read_tail(log_path, show_lines, logger)
        available_keys = load_user_keys(configuration, client_id)
        if available_keys:
            key_note = ''
        else:
            key_note = '''No keys available - you can add a key for use in
transfers below.'''

        if action.endswith('import'):
            transfer_action = 'import'
        elif action.endswith('export'):
            transfer_action = 'export'
        else:
            transfer_action = 'unknown'

        import_checked, export_checked = 'checked', ''
        toggle_quiet, scroll_to_create = '', ''
        if action in ['fillimport', 'fillexport']:
            if quiet(flags):
                toggle_quiet = '''
<script>
 $("#wrap-tabs").hide();
 $("#quiet-mode-content").show();
</script>
'''
            scroll_to_create = '''
<script>
 $("html, body").animate({
  scrollTop: $("#createtransfer").offset().top
   }, 2000);
</script>
            '''
            if action == 'fillimport':
                import_checked = 'checked'
            elif action == 'fillexport':
                export_checked = 'checked'
                import_checked = ''

        fill_helpers = {
            'import_checked': import_checked,
            'export_checked': export_checked,
            'anon_checked': anon_checked,
            'pw_checked': pw_checked,
            'key_checked': key_checked,
            'transfer_id': transfer_id,
            'protocol': protocol,
            'fqdn': fqdn,
            'port': port,
            'username': username,
            'password': password,
            'key_id': key_id,
            'transfer_src_string': ', '.join(src_list),
            'transfer_src': src_list,
            'transfer_dst': dst,
            'exclude': exclude_list,
            'compress': use_compress,
            'notify': notify,
            'toggle_quiet': toggle_quiet,
            'scroll_to_create': scroll_to_create,
            'transfer_action': transfer_action,
            'form_method': form_method,
            'csrf_field': csrf_field,
            'csrf_limit': csrf_limit,
            'target_op': target_op,
            'csrf_token': csrf_token
        }

        # Make page with manage transfers tab and manage keys tab

        output_objects.append({
            'object_type':
            'html_form',
            'text':
            '''
    <div id="quiet-mode-content" class="hidden">
        <p>
        Accept data %(transfer_action)s of %(transfer_src_string)s from
        %(protocol)s://%(fqdn)s:%(port)s/ into %(transfer_dst)s ?
        </p>
        <p>
            <input type=button onClick="doSubmit();"
            value="Accept %(transfer_action)s" />
        </p>
    </div>
    <div id="wrap-tabs" class="datatransfer-tabs">
<ul>
<li><a href="#transfer-tab">Manage Data Transfers</a></li>
<li><a href="#keys-tab">Manage Transfer Keys</a></li>
</ul>
''' % fill_helpers
        })

        # Display external transfers, log and form to add new ones

        output_objects.append({
            'object_type': 'html_form',
            'text': '''
<div id="transfer-tab">
'''
        })

        output_objects.append({
            'object_type': 'sectionheader',
            'text': 'External Data Transfers'
        })
        output_objects.append({
            'object_type': 'table_pager',
            'id_prefix': 'datatransfers_',
            'entry_name': 'transfers',
            'default_entries': default_pager_entries
        })
        output_objects.append({
            'object_type': 'datatransfers',
            'datatransfers': datatransfers
        })
        output_objects.append({
            'object_type': 'sectionheader',
            'text': 'Latest Transfer Results'
        })
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            '''
<textarea id="logarea" class="fillwidth" rows=5 readonly="readonly">%s</textarea>
''' % (''.join(log_lines))
        })
        output_objects.append({
            'object_type': 'sectionheader',
            'text': 'Create External Data Transfer'
        })
        transfer_html = '''
<table class="addexttransfer">
<tr><td>
Fill in the import/export data transfer details below to request a new
background data transfer task.<br/>  
Source must be a path without wildcard characters and it must be specifically
pointed out if the src is a directory. In that case recursive transfer will
automatically be used and otherwise the src is considered a single file, so it
will fail if that is not the case.<br/>  
Destination is a single location directory to transfer the data to. It is
considered in relation to your user home for <em>import</em> requests. Source
is similarly considered in relation to your user home in <em>export</em>
requests.<br/>
Destination is a always handled as a directory path to transfer source files
into.<br/>
<form method="%(form_method)s" action="%(target_op)s.py"
    onSubmit="return beforeSubmit();">
<input type="hidden" name="%(csrf_field)s" value="%(csrf_token)s" />
<fieldset id="transferbox">
<table id="createtransfer" class="addexttransfer">
<tr><td>
<label for="action">Action</label>
<input type=radio name=action %(import_checked)s value="import" />import data
<input type=radio name=action %(export_checked)s value="export" />export data
</td></tr>
<tr><td>
<label for="transfer_id">Optional Transfer ID / Name </label>
<input type=text size=60 name=transfer_id value="%(transfer_id)s"
    pattern="[a-zA-Z0-9._-]*"
    title="Optional ID string containing only ASCII letters and digits possibly with separators like hyphen, underscore and period" />
</td></tr>
<tr><td>
<label for="protocol">Protocol</label>
<select id="protocol_select" class="protocol-select themed-select html-select"
    name="protocol" onblur="setDefaultPort();">
'''
        # select requested protocol
        for (key, val) in valid_proto:
            if protocol == key:
                selected = 'selected'
            else:
                selected = ''
            transfer_html += '<option %s value="%s">%s</option>' % \
                             (selected, key, val)
        transfer_html += '''
</select>
</td></tr>
<tr><td>
<label for="fqdn">Host and port</label>
<input type=text size=37 name=fqdn value="%(fqdn)s" required
    pattern="[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)+"
    title="A fully qualified domain name or Internet IP address for the remote location"/>
<input id="port_input" type=number step=1 min=1 max=65535 name=port
    value="%(port)s" required />
</td></tr>
<tr><td>
<label for="">Login method</label>
<input id="anonymous_choice" type=radio %(anon_checked)s
    onclick="enableLogin(\'anonymous\');" />
anonymous access
<input id="userpassword_choice" type=radio %(pw_checked)s
    onclick="enableLogin(\'password\');" />
login with password
<input id="userkey_choice" type=radio %(key_checked)s
    onclick="enableLogin(\'key\');" />
login with key
</td></tr>
<tr id="login_fields" style="display: none;"><td>
<label for="username">Username</label>
<input id="username" type=text size=60 name=username value="%(username)s"
    pattern="[a-zA-Z0-9._-]*"
    title="Optional username used to login on the remote site, if required" />
<br/>
<span id="password_entry">
<label for="transfer_pw">Password</label>
<input id="password" type=password size=60 name=transfer_pw value="" />
</span>
<span id="key_entry">
<label for="key_id">Key</label>
<select id="key" class="key-select themed-select html-select" name=key_id />
'''
        # select requested key
        for key_dict in available_keys:
            if key_dict['key_id'] == key_id:
                selected = 'selected'
            else:
                selected = ''
            transfer_html += '<option %s value="%s">%s</option>' % \
                             (selected, key_dict['key_id'], key_dict['key_id'])
            selected = ''
        transfer_html += '''
</select> %s
''' % key_note
        transfer_html += '''
</span>
</td></tr>
<tr><td>
<div id="srcfields">
<!-- NOTE: automatically filled by addSource function -->
</div>
<input id="addsrcbutton" type="button" onclick="addSource(); return false;"
    value="Add another source field" />
</td></tr>
<tr><td>
<label for="transfer_dst">Destination path</label>
<input id=\'dst_0\' type=text size=60 name=transfer_dst
    value="%(transfer_dst)s" required
    title="relative destination path: local for imports and remote for exports" />
<input id=\'dst_dir_0\' type=radio checked />Destination directory
<input id=\'dst_file_0\' type=radio disabled />Destination file<br />
</td></tr>
<tr><td>
<div id="excludefields">
<!-- NOTE: automatically filled by addExclude function -->
</div>
<input id="addexcludebutton" type="button" onclick="addExclude(); return false;"
    value="Add another exclude field" />
</td></tr>
<tr><td>
<label for="compress">Enable compression (leave unset except for <em>slow</em> sites)</label>
<input type=checkbox name=compress>
</td></tr>
<tr><td>
<label for="notify">Optional notify on completion (e.g. email address)</label>
<input type=text size=60 name=notify value=\'%(notify)s\'>
</td></tr>
<tr><td>
<span>
<input id="submit-request-transfer" type=submit value="Request transfer" />
<input type=reset value="Clear" />
</span>
</td></tr>
</table>
</fieldset>
</form>
</td>
</tr>
</table>
%(toggle_quiet)s
%(scroll_to_create)s
'''
        output_objects.append({
            'object_type': 'html_form',
            'text': transfer_html % fill_helpers
        })
        output_objects.append({
            'object_type': 'html_form',
            'text': '''
</div>
'''
        })

        # Display key management

        output_objects.append({
            'object_type': 'html_form',
            'text': '''
<div id="keys-tab">
'''
        })
        output_objects.append({
            'object_type': 'sectionheader',
            'text': 'Manage Data Transfer Keys'
        })
        key_html = '''
<form method="%(form_method)s" action="%(target_op)s.py">
<input type="hidden" name="%(csrf_field)s" value="%(csrf_token)s" />
<table class="managetransferkeys">
<tr><td>
'''
        transferkeys = []
        for key_dict in available_keys:
            key_item = build_keyitem_object(configuration, key_dict)
            saved_id = key_item['key_id']
            js_name = 'delete%s' % hexlify(saved_id)
            helper = html_post_helper(js_name, '%s.py' % target_op, {
                'key_id': saved_id,
                'action': 'delkey',
                csrf_field: csrf_token
            })
            output_objects.append({'object_type': 'html_form', 'text': helper})
            key_item['delkeylink'] = {
                'object_type':
                'link',
                'destination':
                "javascript: confirmDialog(%s, '%s');" %
                (js_name, 'Really remove %s?' % saved_id),
                'class':
                'removelink iconspace',
                'title':
                'Remove %s' % saved_id,
                'text':
                ''
            }
            transferkeys.append(key_item)

        output_objects.append({
            'object_type': 'table_pager',
            'id_prefix': 'transferkeys_',
            'entry_name': 'keys',
            'default_entries': default_pager_entries
        })
        output_objects.append({
            'object_type': 'transferkeys',
            'transferkeys': transferkeys
        })

        key_html += '''
Please copy the public key to your ~/.ssh/authorized_keys or
~/.ssh/authorized_keys2 file on systems where you want to login with the
corresponding key.<br/>
%s
</td></tr>
<tr><td>
Select a name below to create a new key for use in future transfers. The key is
generated and stored in a private storage area on %s, so that only the transfer
service can access and use it for your transfers.
</td></tr>
<tr><td>
<input type=hidden name=action value="generatekey" />
Key name:<br/>
<input type=text size=60 name=key_id value="" required pattern="[a-zA-Z0-9._-]+"
    title="internal name for the key when used in transfers. I.e. letters and digits separated only by underscores, periods and hyphens" />
<br/>
<input type=submit value="Generate key" />
</td></tr>
</table>
</form>
''' % (restrict_template % 'ssh-rsa AAAAB3NzaC...', configuration.short_title)
        output_objects.append({
            'object_type': 'html_form',
            'text': key_html % fill_helpers
        })
        output_objects.append({
            'object_type': 'html_form',
            'text': '''
</div>
'''
        })

        output_objects.append({
            'object_type': 'html_form',
            'text': '''
</div>
'''
        })
        return (output_objects, returnvalues.OK)
    elif action in transfer_actions:
        # NOTE: all path validation is done at run-time in grid_transfers
        transfer_dict = transfer_map.get(transfer_id, {})
        if action == 'deltransfer':
            if transfer_dict is None:
                output_objects.append({
                    'object_type':
                    'error_text',
                    'text':
                    'existing transfer_id is required for delete'
                })
                return (output_objects, returnvalues.CLIENT_ERROR)
            (save_status, _) = delete_data_transfer(configuration, client_id,
                                                    transfer_id, transfer_map)
            desc = "delete"
        elif action == 'redotransfer':
            if transfer_dict is None:
                output_objects.append({
                    'object_type':
                    'error_text',
                    'text':
                    'existing transfer_id is required for reschedule'
                })
                return (output_objects, returnvalues.CLIENT_ERROR)
            transfer_dict['status'] = 'NEW'
            (save_status, _) = update_data_transfer(configuration, client_id,
                                                    transfer_dict,
                                                    transfer_map)
            desc = "reschedule"
        else:
            if not fqdn:
                output_objects.append({
                    'object_type': 'error_text',
                    'text': 'No host address provided!'
                })
                return (output_objects, returnvalues.CLIENT_ERROR)
            if not [src for src in src_list if src] or not dst:
                output_objects.append({
                    'object_type':
                    'error_text',
                    'text':
                    'transfer_src and transfer_dst parameters '
                    'required for all data transfers!'
                })
                return (output_objects, returnvalues.CLIENT_ERROR)
            if protocol == "rsyncssh" and not key_id:
                output_objects.append({
                    'object_type':
                    'error_text',
                    'text':
                    'RSYNC over SSH is only supported with key!'
                })
                return (output_objects, returnvalues.CLIENT_ERROR)
            if not password and not key_id and protocol in warn_anon:
                output_objects.append({
                    'object_type':
                    'warning',
                    'text':
                    '''
%s transfers usually require explicit authentication with your credentials.
Proceeding as requested with anonymous login, but the transfer is likely to
fail.''' % valid_proto_map[protocol]
                })
            if key_id and protocol in warn_key:
                output_objects.append({
                    'object_type':
                    'warning',
                    'text':
                    '''
%s transfers usually only support authentication with username and password
rather than key. Proceeding as requested, but the transfer is likely to
fail if it really requires login.''' % valid_proto_map[protocol]
                })

            # Make pseudo-unique ID based on msec time since epoch if not given
            if not transfer_id:
                transfer_id = "transfer-%d" % (time.time() * 1000)
            if transfer_dict:
                desc = "update"
            else:
                desc = "create"

            if password:
                # We don't want to store password in plain text on disk
                password_digest = make_digest('datatransfer', client_id,
                                              password,
                                              configuration.site_digest_salt)
            else:
                password_digest = ''
            transfer_dict.update({
                'transfer_id': transfer_id,
                'action': action,
                'protocol': protocol,
                'fqdn': fqdn,
                'port': port,
                'username': username,
                'password_digest': password_digest,
                'key': key_id,
                'src': src_list,
                'dst': dst,
                'exclude': exclude_list,
                'compress': use_compress,
                'notify': notify,
                'status': 'NEW'
            })
            (save_status, _) = create_data_transfer(configuration, client_id,
                                                    transfer_dict,
                                                    transfer_map)
        if not save_status:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Error in %s data transfer %s: ' % (desc, transfer_id) +
                'save updated transfers failed!'
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

        output_objects.append({
            'object_type':
            'text',
            'text':
            '%sd transfer request %s.' % (desc.title(), transfer_id)
        })
        if action != 'deltransfer':
            output_objects.append({
                'object_type':
                'link',
                'destination':
                "fileman.py?path=transfer_output/%s/" % transfer_id,
                'title':
                'Transfer status and output',
                'text':
                'Transfer status and output folder'
            })
            output_objects.append({
                'object_type':
                'text',
                'text':
                '''
Please note that the status files only appear after the transfer starts, so it
may be empty now.
'''
            })
        logger.debug('datatransfer %s from %s done: %s' %
                     (action, client_id, transfer_dict))
    elif action in key_actions:
        if action == 'generatekey':
            (gen_status, pub) = generate_user_key(configuration, client_id,
                                                  key_id)
            if gen_status:
                output_objects.append({
                    'object_type':
                    'html_form',
                    'text':
                    '''
Generated new key with name %s and associated public key:<br/>
<textarea class="publickey" rows="5" readonly="readonly">%s</textarea>
<p>
Please copy it to your ~/.ssh/authorized_keys or ~/.ssh/authorized_keys2 file
on the host(s) where you want to use this key for background transfer login.
<br/>
%s
</p>
''' % (key_id, pub, restrict_template % pub)
                })
            else:
                output_objects.append({
                    'object_type':
                    'error_text',
                    'text':
                    '''
Key generation for name %s failed with error: %s''' % (key_id, pub)
                })
                return (output_objects, returnvalues.CLIENT_ERROR)
        elif action == 'delkey':
            pubkey = '[unknown]'
            available_keys = load_user_keys(configuration, client_id)
            for key_dict in available_keys:
                if key_dict['key_id'] == key_id:
                    pubkey = key_dict.get('public_key', pubkey)
            (del_status, msg) = delete_user_key(configuration, client_id,
                                                key_id)
            if del_status:
                output_objects.append({
                    'object_type':
                    'html_form',
                    'text':
                    '''
<p>
Deleted the key "%s" and the associated public key:<br/>
</p>
<textarea class="publickey" rows="5" readonly="readonly">%s</textarea>
<p>
You will no longer be able to use it in your data transfers and can safely
remove the public key from your ~/.ssh/authorized_keys* files on any hosts
where you may have previously added it.
</p>
''' % (key_id, pubkey)
                })
            else:
                output_objects.append({
                    'object_type':
                    'error_text',
                    'text':
                    '''
Key removal for name %s failed with error: %s''' % (key_id, msg)
                })
                return (output_objects, returnvalues.CLIENT_ERROR)
    else:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'Invalid data transfer action: %s' % action
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    output_objects.append({
        'object_type': 'link',
        'destination': 'datatransfer.py',
        'text': 'Return to data transfers overview'
    })

    return (output_objects, returnvalues.OK)
Exemplo n.º 22
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)

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'People'

    # 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: 640,
                buttons: {
                   "Cancel": function() { $( "#" + name ).dialog("close"); }
                }
              });

          // table initially sorted by 0 (name)
          var sortOrder = [[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;
          }

          $("#usertable").tablesorter({widgets: ["zebra", "saveSort"],
                                        sortList:sortOrder,
                                        textExtraction: imgTitle
                                        })
                               .tablesorterPager({ container: $("#pager"),
                                        size: %s
                                        });
     }
);
</script>
''' % default_pager_entries

    output_objects.append({'object_type': 'html_form',
                           'text':'''
 <div id="confirm_dialog" title="Confirm" style="background:#fff;">
  <div id="confirm_text"><!-- filled by js --></div>
   <textarea cols="72" rows="10" id="confirm_input" style="display:none;"></textarea>
 </div>
'''                       })

    output_objects.append({'object_type': 'header', 'text'
                          : 'People'})

    output_objects.append(
        {'object_type': 'text', 'text' :
         'View and communicate with other users.'
         })

    output_objects.append({'object_type': 'sectionheader', 'text'
                          : 'All users'})

    visible_user = user_visible_user_confs(configuration, client_id)
    allow_vgrids = user_allowed_vgrids(configuration, client_id)
    anon_map = anon_to_real_user_map(configuration.user_home)
    if not visible_user:
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'no users found!'})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    users = []
    for (visible_user_id, user_dict) in visible_user.items():
        user_id = visible_user_id
        if visible_user_id in anon_map.keys():
            user_id = anon_map[visible_user_id]
        user_obj = {'object_type': 'user', 'name': visible_user_id}
        user_obj.update(user_dict)        
        user_obj['userdetailslink'] = \
                                    {'object_type': 'link',
                                     'destination':
                                     'viewuser.py?cert_id=%s'\
                                     % quote(visible_user_id),
                                     'class': 'infolink',
                                     'title': 'View details for %s' % \
                                     visible_user_id, 
                                     'text': ''}
        vgrids_allow_email = user_dict[CONF].get('VGRIDS_ALLOW_EMAIL', [])
        vgrids_allow_im = user_dict[CONF].get('VGRIDS_ALLOW_IM', [])
        if any_vgrid in vgrids_allow_email:
            email_vgrids = allow_vgrids
        else:
            email_vgrids = set(vgrids_allow_email).intersection(allow_vgrids)
        if any_vgrid in vgrids_allow_im:
            im_vgrids = allow_vgrids
        else:
            im_vgrids = set(vgrids_allow_im).intersection(allow_vgrids)
        for proto in configuration.notify_protocols:
            if not email_vgrids and proto == 'email':
                continue
            if not im_vgrids and proto != 'email':
                continue
            if user_obj[CONF].get(proto.upper(), None):
                js_name = 'send%s%s' % (proto, hexlify(visible_user_id))
                helper = html_post_helper(js_name, 'sendrequestaction.py',
                                          {'cert_id': visible_user_id,
                                           'request_type': 'plain',
                                           'protocol': proto,
                                           'request_text': ''})
                output_objects.append({'object_type': 'html_form', 'text':
                                       helper})
                link = 'send%slink' % proto
                user_obj[link] = {'object_type': 'link',
                                  'destination':
                                  "javascript: confirmDialog(%s, '%s', '%s');"\
                                  % (js_name, 'Really send %s message to %s?'\
                                     % (proto, visible_user_id),
                                     'request_text'),
                                  'class': link,
                                  'title': 'Send %s message to %s' % \
                                  (proto, visible_user_id), 
                                  'text': ''}
        users.append(user_obj)

    output_objects.append({'object_type': 'table_pager', 'entry_name': 'people',
                           'default_entries': default_pager_entries})
    output_objects.append({'object_type': 'user_list',
                          'users': users})

    return (output_objects, returnvalues.OK)
Exemplo n.º 23
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')
    label = "%s" % configuration.site_vgrid_label
    title_entry['text'] = "Create Archive"
    # NOTE: Delay header entry here to include freeze flavor
    # All non-file fields must be validated
    validate_args = dict([(key, user_arguments_dict.get(key, val)) for
                          (key, val) in defaults.items()])
    # IMPORTANT: we must explicitly inlude CSRF token
    validate_args[csrf_field] = user_arguments_dict.get(csrf_field, [
                                                        'AllowMe'])
    (validate_status, accepted) = validate_input_and_cert(
        validate_args,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
    )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    flavor = accepted['flavor'][-1].strip()
    freeze_state = accepted['freeze_state'][-1].strip()

    if not safe_handler(configuration, 'post', op_name, client_id,
                        get_csrf_limit(configuration), accepted):
        output_objects.append(
            {'object_type': 'error_text', 'text': '''Only accepting
CSRF-filtered POST requests to prevent unintended updates'''
             })
        return (output_objects, returnvalues.CLIENT_ERROR)

    if not flavor in freeze_flavors.keys():
        output_objects.append({'object_type': 'error_text', 'text':
                               'Invalid freeze flavor: %s' % flavor})
        return (output_objects, returnvalues.CLIENT_ERROR)
    if not freeze_state in freeze_flavors[flavor]['states'] + [keyword_auto]:
        output_objects.append({'object_type': 'error_text', 'text':
                               'Invalid freeze state: %s' % freeze_state})
        return (output_objects, returnvalues.CLIENT_ERROR)

    title = freeze_flavors[flavor]['createfreeze_title']
    output_objects.append({'object_type': 'header', 'text': title})

    if not configuration.site_enable_freeze:
        output_objects.append({'object_type': 'text', 'text':
                               '''Freezing archives is disabled on this site.
Please contact the site admins %s if you think it should be enabled.
''' % configuration.admin_email})
        return (output_objects, returnvalues.OK)

    # jquery support for confirmation on freeze
    (add_import, add_init, add_ready) = man_base_js(configuration, [])
    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)})

    freeze_id = accepted['freeze_id'][-1].strip()
    freeze_name = accepted['freeze_name'][-1].strip()
    freeze_description = accepted['freeze_description'][-1]
    freeze_author = accepted['freeze_author'][-1].strip()
    freeze_department = accepted['freeze_department'][-1].strip()
    freeze_organization = accepted['freeze_organization'][-1].strip()
    freeze_publish = accepted['freeze_publish'][-1].strip()
    do_publish = (freeze_publish.lower() in ('on', 'true', 'yes', '1'))

    # Share init of base meta with lookup of default state in freeze_flavors
    if not freeze_state or freeze_state == keyword_auto:
        freeze_state = freeze_flavors[flavor]['states'][0]
    freeze_meta = {'ID': freeze_id, 'STATE': freeze_state}

    # New archives must have name and description set
    if freeze_id == keyword_auto:
        logger.debug("creating a new %s archive for %s" % (flavor, client_id))
        if not freeze_name or freeze_name == keyword_auto:
            freeze_name = '%s-%s' % (flavor, datetime.datetime.now())
        if not freeze_description:
            if flavor == 'backup':
                freeze_description = 'manual backup archive created on %s' % \
                                     datetime.datetime.now()
            else:
                output_objects.append(
                    {'object_type': 'error_text', 'text':
                     'You must provide a description for the archive!'})
                return (output_objects, returnvalues.CLIENT_ERROR)
        if flavor == 'phd' and (not freeze_author or not freeze_department):
            output_objects.append({'object_type': 'error_text', 'text': """
You must provide author and department for the thesis!"""})
            return (output_objects, returnvalues.CLIENT_ERROR)
        freeze_meta.update(
            {'FLAVOR': flavor, 'NAME': freeze_name,
             'DESCRIPTION': freeze_description,
             'AUTHOR': freeze_author, 'DEPARTMENT': freeze_department,
             'ORGANIZATION': freeze_organization, 'PUBLISH': do_publish})
    elif is_frozen_archive(client_id, freeze_id, configuration):
        logger.debug("updating existing %s archive for %s" % (flavor,
                                                              client_id))
        # Update any explicitly provided fields (may be left empty on finalize)
        changes = {}
        if freeze_name and freeze_name != keyword_auto:
            changes['NAME'] = freeze_name
        if freeze_author:
            changes['AUTHOR'] = freeze_author
        if freeze_description:
            changes['DESCRIPTION'] = freeze_description
        if freeze_publish:
            changes['PUBLISH'] = do_publish
        logger.debug("updating existing %s archive for %s with: %s" %
                     (flavor, client_id, changes))
        logger.debug("publish is %s based on %s" %
                     (do_publish, freeze_publish))
        freeze_meta.update(changes)
    else:
        logger.error("no such %s archive for %s: %s" % (flavor, client_id,
                                                        freeze_id))
        output_objects.append({'object_type': 'error_text', 'text': """
Invalid archive ID %s - you must either create a new archive or edit an
existing archive of yours!""" % freeze_id})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # Now parse and validate files to archive

    for name in defaults.keys():
        if user_arguments_dict.has_key(name):
            del user_arguments_dict[name]

    (copy_files, copy_rejected) = parse_form_copy(user_arguments_dict,
                                                  client_id, configuration)
    (move_files, move_rejected) = parse_form_move(user_arguments_dict,
                                                  client_id, configuration)
    (upload_files, upload_rejected) = parse_form_upload(user_arguments_dict,
                                                        client_id,
                                                        configuration)
    if copy_rejected + move_rejected + upload_rejected:
        output_objects.append({'object_type': 'error_text', 'text':
                               'Errors parsing freeze files: %s' %
                               '\n '.join(copy_rejected + move_rejected +
                                          upload_rejected)})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # NOTE: this may be a new or an existing pending archive, and it will fail
    #       if archive is already under update
    (retval, retmsg) = create_frozen_archive(freeze_meta, copy_files,
                                             move_files, upload_files,
                                             client_id, configuration)
    if not retval:
        output_objects.append({'object_type': 'error_text', 'text':
                               'Error creating/updating archive: %s'
                               % retmsg})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    # Make sure we have freeze_id and other updated fields
    freeze_meta.update(retmsg)
    freeze_id = freeze_meta['ID']
    logger.info("%s: successful for '%s': %s" % (op_name,
                                                 freeze_id, client_id))
    # Return simple status mainly for use in scripting
    output_objects.append({'object_type': 'freezestatus', 'freeze_id': freeze_id,
                           'flavor': flavor, 'freeze_state': freeze_state})
    publish_note = ''
    if freeze_state == keyword_pending:
        publish_hint = 'Preview published archive page in a new window/tab'
        publish_text = 'Preview publishing'
        output_objects.append({'object_type': 'text', 'text': """
Saved *preliminary* %s archive with ID %s . You can continue inspecting and
changing it until you're satisfied, then finalize it for actual persistent
freezing.""" % (flavor, freeze_id)})
    else:
        publish_hint = 'View published archive page in a new window/tab'
        publish_text = 'Open published archive'
        output_objects.append({'object_type': 'text', 'text':
                               'Successfully froze %s archive with ID %s .'
                               % (flavor, freeze_id)})

    if do_publish:
        public_url = published_url(freeze_meta, configuration)
        output_objects.append({'object_type': 'text', 'text': ''})
        output_objects.append({
            'object_type': 'link',
            'destination': public_url,
            'class': 'previewarchivelink iconspace genericbutton',
            'title': publish_hint,
            'text': publish_text,
            'target': '_blank',
        })
        output_objects.append({'object_type': 'text', 'text': ''})

    # Always allow show archive
    output_objects.append({
        'object_type': 'link',
        'destination': 'showfreeze.py?freeze_id=%s;flavor=%s' % (freeze_id,
                                                                 flavor),
        'class': 'viewarchivelink iconspace genericbutton',
        'title': 'View details about your %s archive' % flavor,
        'text': 'View details',
    })

    if freeze_state == keyword_pending:
        output_objects.append({'object_type': 'text', 'text': ''})
        output_objects.append({
            'object_type': 'link',
            'destination': 'adminfreeze.py?freeze_id=%s' % freeze_id,
            'class': 'editarchivelink iconspace genericbutton',
            'title': 'Further modify your pending %s archive' % flavor,
            'text': 'Edit archive',
        })
        output_objects.append({'object_type': 'text', 'text': ''})
        output_objects.append({'object_type': 'html_form', 'text': """
<br/><hr/><br/>
<p class='warn_message'>IMPORTANT: you still have to explicitly finalize your
archive before you get the additional data integrity/persistance guarantees
like tape archiving.
</p>"""})

        form_method = 'post'
        target_op = 'createfreeze'
        csrf_limit = get_csrf_limit(configuration)
        csrf_token = make_csrf_token(configuration, form_method, target_op,
                                     client_id, csrf_limit)
        helper = html_post_helper('createfreeze', '%s.py' % target_op,
                                  {'freeze_id': freeze_id,
                                   'freeze_state': keyword_final,
                                   'flavor': flavor,
                                   csrf_field: csrf_token})
        output_objects.append({'object_type': 'html_form', 'text': helper})

        output_objects.append({
            'object_type': 'link',
            'destination':
            "javascript: confirmDialog(%s, '%s');" %
            ('createfreeze', 'Really finalize %s?' % freeze_id),
            'class': 'finalizearchivelink iconspace genericbutton',
            'title': 'Finalize %s archive to prevent further changes' % flavor,
            'text': 'Finalize archive',
        })

    return (output_objects, returnvalues.OK)
Exemplo n.º 24
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)
    action = accepted['action'][-1]
    req_list = accepted['req_id']
    job_list = accepted['job_id']
    lines = int(accepted['lines'][-1])

    meta = '''<meta http-equiv="refresh" content="%s" />
''' % configuration.sleep_secs
    style = themed_styles(configuration)
    script = '''
<script type="text/javascript" src="/images/js/jquery.js"></script>
<script type="text/javascript" src="/images/js/jquery.tablesorter.js"></script>
<script type="text/javascript" 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. 9 (created)
          var sortOrder = [[9,0]];

          $("#certreqtable").tablesorter({widgets: ["zebra", "saveSort"],
                                        sortList:sortOrder
                                        })
                               .tablesorterPager({ container: $("#pager"),
                                        size: %s
                                        });
     }
);
</script>
''' % default_pager_entries

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = '%s administration panel' % configuration.short_title
    title_entry['meta'] = meta
    title_entry['style'] = style
    title_entry['javascript'] = script

    output_objects.append({'object_type': 'html_form',
                           'text':'''
 <div id="confirm_dialog" title="Confirm" style="background:#fff;">
  <div id="confirm_text"><!-- filled by js --></div>
   <textarea cols="40" rows="4" id="confirm_input"
       style="display:none;"></textarea>
 </div>
'''                       })

    if not is_admin(client_id, configuration, logger):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'You must be an admin to access this control panel.'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    html = ''
    if action and not action in grid_actions.keys() + certreq_actions:
        output_objects.append({'object_type': 'error_text', 'text'
                               : 'Invalid action: %s' % action})
        return (output_objects, returnvalues.SYSTEM_ERROR)
    if action in grid_actions:
        msg = "%s" % grid_actions[action]
        if job_list:
            msg += ' %s' % ' '.join(job_list)
        msg += '\n'
        if not send_message_to_grid_script(msg, logger, configuration):
            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : '''Error sending %s message to grid_script.''' % action
                 })
            status = returnvalues.SYSTEM_ERROR
    elif action in certreq_actions:
        if action == "addcertreq":
            for req_id in req_list:
                if accept_cert_req(req_id, configuration):
                    output_objects.append(
                        {'object_type': 'text', 'text':
                         'Accepted certificate request %s' % req_id})
                else:
                    output_objects.append(
                        {'object_type': 'error_text', 'text':
                         'Accept certificate request failed - details in log'
                         })
        elif action == "delcertreq":
            for req_id in req_list:
                if delete_cert_req(req_id, configuration):
                    output_objects.append(
                        {'object_type': 'text', 'text':
                         'Deleted certificate request %s' % req_id})
                else:
                    output_objects.append(
                        {'object_type': 'error_text', 'text':
                         'Delete certificate request failed - details in log'
                         })

    show, drop = '', ''
    general = """
<h1>Server Status</h1>
<p class='importanttext'>
This page automatically refreshes every %s seconds.
</p>
<p>
You can see the current grid daemon status and server logs below. The buttons
provide access to e.g. managing the grid job queues.
</p>
<form method='get' action='migadmin.py'>
    <input type='hidden' name='action' value='' />
    <input type='submit' value='Show last log lines' />
    <input type='text' size='2' name='lines' value='%s' />
</form>
<br />
<form method='get' action='migadmin.py'>
    <input type='hidden' name='lines' value='%s' />
    <input type='hidden' name='action' value='reloadconfig' />
    <input type='submit' value='Reload Configuration' />
</form>
<br />
""" % (configuration.sleep_secs, lines, lines)
    show += """
<form method='get' action='migadmin.py'>
    <input type='hidden' name='lines' value='%s' />
    <input type='submit' value='Log Jobs' />
    <select name='action'>
""" % lines
    drop += """
<form method='get' action='migadmin.py'>
    <input type='hidden' name='lines' value='%s' />
    <input type='submit' value='Drop Job' />
    <select name='action'>
""" % lines
    for queue in ['queued', 'executing', 'done']:
        selected = ''
        if action.find(queue) != -1:
            selected = 'selected'
        show += "<option %s value='show%s'>%s</option>" % (selected, queue,
                                                             queue)
        drop += "<option %s value='drop%s'>%s</option>" % (selected, queue,
                                                             queue)
    show += """
    </select>
</form>
<br />
"""
    drop += """
    </select>
    <input type='text' size='20' name='job_id' value='' />
</form>
<br />
"""
    html += general
    html += show
    html += drop

    daemons = """
<div id='daemonstatus'>
"""
    daemon_names = ['grid_script.py', 'grid_monitor.py', 'grid_sshmux.py']
    # No need to run im_notify unless any im notify protocols are enabled
    if [i for i in configuration.notify_protocols if i != 'email']:
        daemon_names.append('grid_imnotify.py')
    if configuration.site_enable_sftp:
        daemon_names.append('grid_sftp.py')
    if configuration.site_enable_davs:
        daemon_names.append('grid_webdavs.py')
    if configuration.site_enable_ftps:
        daemon_names.append('grid_ftps.py')
    if configuration.site_enable_openid:
        daemon_names.append('grid_openid.py')
    for proc in daemon_names:
        pgrep_proc = subprocess.Popen(['pgrep', '-f', proc],
                                      stdout=subprocess.PIPE,
                                      stderr=subprocess.STDOUT)
        pgrep_proc.wait()
        ps_out = pgrep_proc.stdout.read().strip()
        if pgrep_proc.returncode == 0:
            daemons += "<div class='status_online'>%s running (pid %s)</div>" \
                       % (proc, ps_out)
        else:
            daemons += "<div class='status_offline'>%s not running!</div>" % \
                       proc
    daemons += """</div>
<br />
"""
    html += daemons
    
    output_objects.append({'object_type': 'header', 'text'
                          : 'Pending Certificate Requests'})

    (status, ret) = list_cert_reqs(configuration)
    if not status:
        logger.error("%s: failed for '%s': %s" % (op_name,
                                                  client_id, ret))
        output_objects.append({'object_type': 'error_text', 'text'
                              : ret})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    certreqs = []
    for req_id in ret:
        (load_status, req_dict) = get_cert_req(req_id, configuration)
        if not load_status:
            logger.error("%s: load failed for '%s': %s" % \
                         (op_name, req_id, req_dict))
            output_objects.append({'object_type': 'error_text', 'text'
                                   : 'Could not read details for "%s"' % \
                                   req_id})
            return (output_objects, returnvalues.SYSTEM_ERROR)
        req_item = build_certreqitem_object(configuration, req_dict)
        
        js_name = 'create%s' % req_id
        helper = html_post_helper(js_name, 'migadmin.py',
                                  {'action': 'addcertreq', 'req_id': req_id})
        output_objects.append({'object_type': 'html_form', 'text': helper})
        req_item['addcertreqlink'] = {
            'object_type': 'link', 'destination':
            "javascript: confirmDialog(%s, '%s');" % \
            (js_name, 'Really accept %s?' % req_id),
            'class': 'addlink', 'title': 'Accept %s' % req_id, 'text': ''}
        js_name = 'delete%s' % req_id
        helper = html_post_helper(js_name, 'migadmin.py',
                                  {'action': 'delcertreq', 'req_id': req_id})
        output_objects.append({'object_type': 'html_form', 'text': helper})
        req_item['delcertreqlink'] = {
            'object_type': 'link', 'destination':
            "javascript: confirmDialog(%s, '%s');" % \
            (js_name, 'Really remove %s?' % req_id),
            'class': 'removelink', 'title': 'Remove %s' % req_id, 'text': ''}
        certreqs.append(req_item)

    output_objects.append({'object_type': 'table_pager', 'entry_name':
                           'pending certificate requests',
                           'default_entries': default_pager_entries})
    output_objects.append({'object_type': 'certreqs',
                          'certreqs': certreqs})

    log_path_list = []
    if os.path.isabs(configuration.logfile):
        log_path_list.append(configuration.logfile)
    else:
        log_path_list.append(os.path.join(configuration.log_dir,
                                          configuration.logfile))
    for log_path in log_path_list:
        html += '''
<h1>%s</h1>
<textarea rows=%s cols=200 readonly="readonly">
''' % (log_path, lines)
        try:
            logger.debug("loading %d lines from %s" % (lines, log_path))
            log_fd = open(log_path, 'r')
            log_fd.seek(0, os.SEEK_END)
            size = log_fd.tell()
            pos = log_fd.tell()
            log_lines = []
            step_size = 100
            # locate last X lines 
            while pos > 0 and len(log_lines) < lines:
                offset = min(lines * step_size, size)
                logger.debug("seek to offset %d from end of %s" % (offset,
                                                                  log_path))
                log_fd.seek(-offset, os.SEEK_END)
                pos = log_fd.tell()
                log_lines = log_fd.readlines()
                step_size *= 2
            logger.debug("reading %d lines from %s" % (lines, log_path))
            html += ''.join(log_lines[-lines:])
            log_fd.close()
        except Exception, exc:
            logger.error("reading %d lines from %s: %s" % (lines, log_path,
                                                           exc))
            output_objects.append({'object_type': 'error_text', 'text'
                                   : 'Error reading log (%s)' % exc})
            return (output_objects, returnvalues.SYSTEM_ERROR)
        html += '''</textarea>
Exemplo n.º 25
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)

    vgrid_name = accepted['vgrid_name'][-1]

    # prepare support for confirm dialog and toggling the views (by css/jquery)

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = "Administrate %s: %s" % \
                          (configuration.site_vgrid_label, vgrid_name)

    title_entry['style'] = themed_styles(configuration)
    title_entry['javascript'] = '''
<script type="text/javascript" src="/images/js/jquery.js"></script>
<script type="text/javascript" src="/images/js/jquery-ui.js"></script>
<script type="text/javascript" src="/images/js/jquery.confirm.js"></script>

<script type="text/javascript" >

    var toggleHidden = function(classname) {
        // classname supposed to have a leading dot 
        $(classname).toggleClass('hidden');
    }

$(document).ready(function() {

          // init confirmation dialog
          $( "#confirm_dialog" ).dialog(
              // see http://jqueryui.com/docs/dialog/ for options
              { autoOpen: false,
                modal: true, closeOnEscape: true,
                width: 500,
                buttons: {
                   "Cancel": function() { $( "#" + name ).dialog("close"); }
                }
              });
     }
);
</script>
'''

    output_objects.append({'object_type': 'html_form',
                           'text':'''
 <div id="confirm_dialog" title="Confirm" style="background:#fff;">
  <div id="confirm_text"><!-- filled by js --></div>
   <textarea cols="40" rows="4" id="confirm_input" style="display:none;"></textarea>
 </div>
'''                       })
    
    output_objects.append({'object_type': 'header', 'text'
                          : "Administrate '%s'" % vgrid_name })

    if not vgrid_is_owner(vgrid_name, client_id, configuration):
        output_objects.append({'object_type': 'error_text', 'text': 
                    'Only owners of %s can administrate it.' % vgrid_name })
        js_name = 'reqvgridowner%s' % hexlify(vgrid_name)
        helper = html_post_helper(js_name, 'sendrequestaction.py',
                                  {'vgrid_name': vgrid_name,
                                   'request_type': 'vgridowner',
                                   'request_text': ''})
        output_objects.append({'object_type': 'html_form', 'text': helper})
        output_objects.append(
            {'object_type': 'link',
             'destination':
             "javascript: confirmDialog(%s, '%s', '%s');"\
             % (js_name, "Request ownership of " + \
                vgrid_name + ":<br/>" + \
                "\nPlease write a message to the owners below.",
                'request_text'),
             'class': 'addadminlink',
             'title': 'Request ownership of %s' % vgrid_name,
             'text': 'Apply to become an owner'})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    for (item, scr) in zip(['owner', 'member', 'resource'],
                        ['vgridowner', 'vgridmember', 'vgridres']):
        output_objects.append({'object_type': 'sectionheader',
                               'text': "%ss" % item.title()
                               })
        if item == 'trigger':
            # Always run as rule creator to avoid users being able to act on
            # behalf of ANY other user using triggers (=exploit)
            extra_fields = [('path', None),
                            ('changes', [keyword_all] + valid_trigger_changes),
                            ('run_as', client_id),
                            ('action', [keyword_auto] + valid_trigger_actions),
                            ('arguments', None)]
        else:
            extra_fields = []

        (status, oobjs) = vgrid_add_remove_table(client_id, vgrid_name, item, 
                                                 scr, configuration,
                                                 extra_fields)
        if not status:
            output_objects.extend(oobjs)
            return (output_objects, returnvalues.SYSTEM_ERROR)
        else:
            output_objects.append({'object_type': 'html_form', 
                                   'text': '<div class="div-%s">' % item })
            output_objects.append(
                {'object_type': 'link', 
                 'destination': 
                 "javascript:toggleHidden('.div-%s');" % item,
                 'class': 'removeitemlink',
                 'title': 'Toggle view',
                 'text': 'Hide %ss' % item.title() })
            output_objects.extend(oobjs)
            output_objects.append(
                {'object_type': 'html_form', 
                 'text': '</div><div class="hidden div-%s">' % item})
            output_objects.append(
                {'object_type': 'link', 
                 'destination': 
                 "javascript:toggleHidden('.div-%s');" % item,
                 'class': 'additemlink',
                 'title': 'Toggle view',
                 'text': 'Show %ss' % item.title() })
            output_objects.append({'object_type': 'html_form', 
                                   'text': '</div>' })

    # Checking/fixing of missing components

    output_objects.append({'object_type': 'sectionheader',
                           'text': "Repair/Add Components"})
    output_objects.append({'object_type': 'html_form',
                           'text': '''
      <form method="post" action="updatevgrid.py">
          <input type="hidden" name="vgrid_name" value="%(vgrid)s" />
          <input type="submit" value="Repair components" />
      </form>
''' % {'vgrid': vgrid_name}})

    output_objects.append({'object_type': 'sectionheader',
                           'text': "Delete %s " % vgrid_name})
    output_objects.append({'object_type': 'html_form',
                           'text': '''
To delete <b>%(vgrid)s</b> remove all members and owners ending with yourself.
''' % {'vgrid': vgrid_name}})

    return (output_objects, returnvalues.OK)
Exemplo n.º 26
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)

    if not correct_handler('POST'):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : 'Only accepting POST requests to prevent unintended updates'})
        return (output_objects, returnvalues.CLIENT_ERROR)

    vgrid_name = accepted['vgrid_name'][-1]
    flags = ''.join(accepted['flags'])
    cert_id = accepted['cert_id'][-1]
    cert_dir = client_id_dir(cert_id)
    # inherited vgrid membership
    inherit_vgrid_member = False

    title_entry = find_entry(output_objects, 'title')
    title_entry['text'] = 'Remove %s' % configuration.site_vgrid_label
    output_objects.append({'object_type': 'header', 'text'
                          : 'Remove %s Owner' % \
                           configuration.site_vgrid_label})

    # Validity of user and vgrid names is checked in this init function so
    # no need to worry about illegal directory traversal through variables

    (ret_val, msg, _) = \
        init_vgrid_script_add_rem(vgrid_name, client_id, cert_id,
                                  'owner', configuration)
    if not ret_val:
        output_objects.append({'object_type': 'error_text', 'text'
                              : msg})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # don't remove if not already an owner

    if not vgrid_is_owner(vgrid_name, cert_id, configuration):
        output_objects.append({'object_type': 'error_text', 'text'
                              : '%s is not an owner of %s or a parent %s.'
                               % (cert_id, vgrid_name,
                                  configuration.site_vgrid_label)})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # we need the local owners file to detect inherited ownerships

    (status, owners_direct) = vgrid_owners(vgrid_name, configuration, False)
    (all_status, owners) = vgrid_owners(vgrid_name, configuration, True)
    if not status or not all_status:
        logger.error('Error loading owners for %s: %s / %s'
                     % (vgrid_name, owners_direct, owners))
        output_objects.append({'object_type': 'error_text', 'text'
         : 'An internal error occurred, error conditions have been logged.'})
        output_objects.append({'object_type': 'text', 'text'
         : '''
         You can help us fix the problem by notifying the administrators
         via mail about what you wanted to do when the error happened.'''})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # find out whether to just remove an owner or delete the whole thing.
    # ask about delete if last or no direct owners.

    if len(owners_direct) > 1:
        
        logger.debug('Removing %s, one of several owners, from %s.' % 
                     (cert_id, vgrid_name))

        if not (cert_id in owners_direct):

            # the owner owns an upper vgrid, ownership is inherited
            # cannot remove, not last (inherited) owner

            logger.debug('Cannot delete: Inherited ownership.' + 
                         '\n Owners: %s,\n Direct owners: %s.' 
                         % (owners, owners_direct))
            output_objects.append({'object_type': 'error_text', 'text'
                                   : '''%s is owner of a parent %s. 
Owner removal has to be performed at the topmost vgrid''' % \
                                   (cert_id, configuration.site_vgrid_label)})
            return (output_objects, returnvalues.CLIENT_ERROR)

        else:

            # Remove any tracker admin rights
            
            if configuration.trac_admin_path:
                public_tracker_dir = \
                                   os.path.abspath(os.path.join(
                    configuration.vgrid_public_base, vgrid_name,
                    '.vgridtracker'))
                private_tracker_dir = \
                                    os.path.abspath(os.path.join(
                    configuration.vgrid_private_base, vgrid_name,
                    '.vgridtracker'))
                vgrid_tracker_dir = \
                                  os.path.abspath(os.path.join(
                    configuration.vgrid_files_home, vgrid_name,
                    '.vgridtracker'))
                for tracker_dir in [public_tracker_dir, private_tracker_dir,
                                    vgrid_tracker_dir]:
                    if not rm_tracker_admin(configuration, cert_id,
                                             vgrid_name, tracker_dir,
                                             output_objects):
                        return (output_objects, returnvalues.SYSTEM_ERROR)

            user_dir = os.path.abspath(os.path.join(configuration.user_home,
                                                    cert_dir)) + os.sep
        
            # Do not touch vgrid share if still a member of a parent vgrid
            
            if vgrid_is_member(vgrid_name, cert_id, configuration):
                # list is in top-down order 
                parent_vgrids = vgrid_list_parents(vgrid_name, configuration)
                inherit_vgrid_member = vgrid_name
                for parent in parent_vgrids:
                    if vgrid_is_member(parent, cert_id, configuration,
                                       recursive=False):
                        inherit_vgrid_member = parent
                        break
                output_objects.append(
                    {'object_type': 'text', 'text'
                     : '''NOTE: %s is still a member of parent %s %s.
                     Preserving access to corresponding %s.''' % \
                     (cert_id, configuration.site_vgrid_label,
                      inherit_vgrid_member, configuration.site_vgrid_label)
                     })
            else:
                (success, msg) = unlink_share(user_dir, vgrid_name)
                if not success: 
                    logger.error('Could not remove share link: %s.' % msg)
                    output_objects.append({'object_type': 'error_text', 'text'
                                           : 'Could not remove share links: %s.'
                                           % msg})
                    return (output_objects, returnvalues.SYSTEM_ERROR)

            # unlink shared web folders

            (success, msg) = unlink_web_folders(user_dir, vgrid_name)
            if not success: 
                logger.error('Could not remove web links: %s.' % msg)
                output_objects.append({'object_type': 'error_text', 'text'
                                       : 'Could not remove web links: %s.' 
                                       % msg})
                return (output_objects, returnvalues.SYSTEM_ERROR)

            # remove user from saved owners list
            (rm_status, rm_msg) = vgrid_remove_owners(configuration, vgrid_name,
                                                     [cert_id])
            if not rm_status:
                output_objects.append({'object_type': 'error_text', 'text'
                                       : '%s of owners of %s' 
                                       % (rm_msg, vgrid_name)})
                return (output_objects, returnvalues.SYSTEM_ERROR)

            # Any parent vgrid membership is left untouched here as we only
            # force a normal refresh in unmap_inheritance
            unmap_inheritance(configuration, vgrid_name, cert_id)

            output_objects.append({'object_type': 'text', 'text'
                          : '%s successfully removed as owner of %s!'
                           % (cert_id, vgrid_name)})
            output_objects.append({'object_type': 'link', 'destination':
                           'adminvgrid.py?vgrid_name=%s' % vgrid_name, 'text':
                           'Back to administration for %s' % vgrid_name})
            return (output_objects, returnvalues.OK)

    else:
        
        # no more direct owners - we try to remove this VGrid

        logger.debug('Leave %s from %s with no more direct owners: delete' %
                     (vgrid_name, cert_id))

        if not force(flags):
            output_objects.append({'object_type': 'text', 'text' : '''
No more direct owners of %s - leaving will result in the %s getting
deleted. Please use either of the links below to confirm or cancel.
''' % (vgrid_name, configuration.site_vgrid_label)})
            js_name = 'rmvgridowner%s' % hexlify(vgrid_name)
            helper = html_post_helper(js_name, 'rmvgridowner.py',
                                      {'vgrid_name': vgrid_name,
                                       'cert_id': cert_id, 'flags': 'f'})
            output_objects.append({'object_type': 'html_form', 'text': helper})
            output_objects.append({'object_type': 'link', 'destination':
                                   "javascript: %s();" % js_name, 'class':
                                   'removelink', 'text':
                                   'Really leave and delete %s' % vgrid_name})
            output_objects.append({'object_type': 'text', 'text' : ''})
            output_objects.append({'object_type': 'link', 'destination':
                                   'adminvgrid.py?vgrid_name=%s' % vgrid_name,
                                   'text': 'Back to administration for %s'
                                   % vgrid_name})
            return (output_objects, returnvalues.OK)

        # check if any resources participate or sub-vgrids depend on this one

        (status, subs) = vgrid_list_subvgrids(vgrid_name, configuration)

        if not status:
            logger.error('Error loading sub-%ss for %s: %s)'
                         % (configuration.site_vgrid_label, vgrid_name, subs))
            output_objects.append({'object_type': 'error_text', 'text' : '''
An internal error occurred, error conditions have been logged.'''})
            output_objects.append({'object_type': 'text', 'text' : '''
You can help us fix the problem by notifying the administrators
via mail about what you wanted to do when the error happened.'''})
            return (output_objects, returnvalues.CLIENT_ERROR)

        if len(subs) > 0:

            logger.debug('Cannot delete: still has sub-%ss %s.'
                         % (configuration.site_vgrid_label, subs))
            output_objects.append({'object_type': 'error_text', 'text' : \
    '%s has sub-structures and cannot be deleted.' % vgrid_name})
            output_objects.append({'object_type': 'text', 'text' : '''
To leave (and delete) %s, first remove its sub-structures: %s.'''
                                      % (vgrid_name, ', '.join(subs))})

            return (output_objects, returnvalues.CLIENT_ERROR)

        # we consider the local members and resources here, not inherited ones
        
        (member_status, members_direct) = vgrid_members(vgrid_name,
                                                        configuration,
                                                        False)
        (resource_status, resources_direct) = vgrid_resources(vgrid_name,
                                                              configuration,
                                                              False)
        if not member_status or not resource_status:
            logger.warning('failed to load %s members or resources: %s %s'
                           % (vgrid_name, members_direct, resources_direct))
            output_objects.append({'object_type': 'error_text', 'text' : \
    'could not load %s members or resources for %s.' % \
                                   (configuration.site_vgrid_label,
                                    vgrid_name)})
            return (output_objects, returnvalues.SYSTEM_ERROR)
        if len(resources_direct) > 0:
            logger.debug('Cannot delete: still has direct resources %s.'
                         % resources_direct)
            output_objects.append({'object_type': 'error_text', 'text' : \
    '%s still has resources and cannot be deleted.' % vgrid_name})
            output_objects.append({'object_type': 'text', 'text' : '''
To leave (and delete) %s, first remove the participating resources.'''
                                      % vgrid_name})

            return (output_objects, returnvalues.CLIENT_ERROR)

        if len(members_direct) > 0:

            logger.debug('Cannot delete: still has direct members %s.'
                         % members_direct)
            output_objects.append({'object_type': 'error_text', 'text' : \
    '%s still has members and cannot be deleted.' % vgrid_name})
            output_objects.append({'object_type': 'text', 'text' : '''
To leave (and delete) %s, first remove all members.'''
                                      % vgrid_name})

            return (output_objects, returnvalues.CLIENT_ERROR)

        # When reaching here, OK to remove the VGrid.
        #   if top-level: unlink, remove all files and directories, 
        #   in all cases: remove configuration entry for the VGrid

        if (cert_id in owners_direct):

            # owner owns this vgrid, direct ownership

            logger.debug('%s looks like a top-level %s.' % \
                         (configuration.site_vgrid_label, vgrid_name))
            logger.debug('Deleting all related files.')

            user_dir = os.path.abspath(os.path.join(configuration.user_home,
                                                    cert_dir)) + os.sep
            (share_lnk, msg1)  = unlink_share(user_dir, vgrid_name)
            (web_lnk, msg1)  = unlink_web_folders(user_dir, vgrid_name)
            (abandoned, msg2) = abandon_vgrid_files(vgrid_name, configuration)
        else:

            # owner owns an upper vgrid, ownership is inherited

            logger.debug('%s looks like a sub-%s, ownership inherited.'
                         % (vgrid_name, configuration.site_vgrid_label))
            logger.debug('Only removing entry, leaving files in place.')
            share_lnk = True
            web_lnk = True
            abandoned = True
            msg1 = ''
            msg2 = ''

        (removed, msg3) = remove_vgrid_entry(vgrid_name, configuration)

        output_objects.append({'object_type': 'text', 'text'
                                   : '%s has been removed with last owner.'
                                      % vgrid_name})

        output_objects.append({'object_type': 'link', 
                               'destination': 'vgridadmin.py', 
                               'text': 'Back to the overview.'})

        if not share_lnk or not web_lnk or not abandoned or not removed:

            logger.error('Errors while removing %s:\n%s.'
                         % (vgrid_name, '\n'.join([msg1,msg2,msg3])))

            output_objects.append({'object_type': 'error_text', 'text' : '''
An internal error occurred, error conditions have been logged.'''})
            output_objects.append({'object_type': 'text', 'text' : '''
You can help us fix the problem by notifying the administrators
via mail about what you wanted to do when the error happened.'''})
            return (output_objects, returnvalues.CLIENT_ERROR)

        else:

            # Remove vgrid from vgrid cache (after deleting all)
            unmap_vgrid(configuration, vgrid_name)
            return (output_objects, returnvalues.OK)
Exemplo n.º 27
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')
    label = "%s" % configuration.site_vgrid_label
    title_entry['text'] = "Administrate %s" % label
    # NOTE: Delay header entry here to include vgrid name
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
    )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    vgrid_name = accepted['vgrid_name'][-1]

    # prepare for confirm dialog, tablesort and toggling the views (css/js)

    # jquery support for tablesorter and confirmation on request and leave
    # requests table initially sorted by 0, 4, 3 (type first, then date and
    # with alphabetical client ID last)
    # sharelinks table initially sorted by 5, 4 reversed (active first and
    # in growing age)

    table_specs = [{
        'table_id': 'accessrequeststable',
        'pager_id': 'accessrequests_pager',
        'sort_order': '[[0,0],[4,0],[3,0]]'
    }, {
        'table_id': 'sharelinkstable',
        'pager_id': 'sharelinks_pager',
        'sort_order': '[[5,1],[4,1]]'
    }]
    (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");
        };
        /* helpers for dynamic form input fields */
        function onOwnerInputChange() {
            makeSpareFields("#dynownerspares", "cert_id");
        }
        function onMemberInputChange() {
            makeSpareFields("#dynmemberspares", "cert_id");
        }
        function onResourceInputChange() {
            makeSpareFields("#dynresourcespares", "unique_resource_name");
        }
    '''
    add_ready += '''
    /* init add owners/member/resource forms with dynamic input fields */
    onOwnerInputChange();
    $("#dynownerspares").on("blur", "input[name=cert_id]",
        function(event) {
            //console.debug("in add owner blur handler");
            onOwnerInputChange();
        }
    );
    onMemberInputChange();
    $("#dynmemberspares").on("blur", "input[name=cert_id]",
        function(event) {
            //console.debug("in add member blur handler");
            onMemberInputChange();
        }
    );'''
    if configuration.site_enable_resources:
        add_ready += '''
    onResourceInputChange();
    $("#dynresourcespares").on("blur", "input[name=unique_resource_name]",
        function(event) {
            console.debug("in resource blur handler");
            onResourceInputChange();
        }
    );
    '''
    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': label,
        'form_method': form_method,
        'csrf_field': csrf_field,
        'csrf_limit': csrf_limit
    }

    output_objects.append({
        'object_type': 'header',
        'text': "Administrate '%s'" % vgrid_name
    })

    if not vgrid_is_owner(vgrid_name, client_id, configuration):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'Only owners of %s can administrate it.' % vgrid_name
        })
        target_op = "sendrequestaction"
        csrf_token = make_csrf_token(configuration, form_method, target_op,
                                     client_id, csrf_limit)
        js_name = 'reqvgridowner%s' % hexlify(vgrid_name)
        helper = html_post_helper(
            js_name, '%s.py' % target_op, {
                'vgrid_name': vgrid_name,
                'request_type': 'vgridowner',
                'request_text': '',
                csrf_field: csrf_token
            })
        output_objects.append({'object_type': 'html_form', 'text': helper})
        output_objects.append({
            'object_type':
            'link',
            'destination':
            "javascript: confirmDialog(%s, '%s', '%s');" %
            (js_name, "Request ownership of " + vgrid_name + ":<br/>" +
             "\nPlease write a message to the owners below.", 'request_text'),
            'class':
            'addadminlink iconspace',
            'title':
            'Request ownership of %s' % vgrid_name,
            'text':
            'Apply to become an owner'
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)

    for (item, scr) in zip(['owner', 'member', 'resource'],
                           ['vgridowner', 'vgridmember', 'vgridres']):
        if item == 'resource' and not configuration.site_enable_resources:
            continue
        output_objects.append({
            'object_type': 'sectionheader',
            'text': "%ss" % item.title()
        })
        (init_status, oobjs) = vgrid_add_remove_table(client_id, vgrid_name,
                                                      item, scr, configuration)
        if not init_status:
            output_objects.extend(oobjs)
            return (output_objects, returnvalues.SYSTEM_ERROR)
        else:
            output_objects.append({
                'object_type': 'html_form',
                'text': '<div class="div-%s">' % item
            })
            output_objects.append({
                'object_type':
                'link',
                'destination':
                "javascript:toggleHidden('.div-%s');" % item,
                'class':
                'removeitemlink iconspace',
                'title':
                'Toggle view',
                'text':
                'Hide %ss' % item.title()
            })
            output_objects.extend(oobjs)
            output_objects.append({
                'object_type':
                'html_form',
                'text':
                '</div><div class="hidden div-%s">' % item
            })
            output_objects.append({
                'object_type':
                'link',
                'destination':
                "javascript:toggleHidden('.div-%s');" % item,
                'class':
                'additemlink iconspace',
                'title':
                'Toggle view',
                'text':
                'Show %ss' % item.title()
            })
            output_objects.append({
                'object_type': 'html_form',
                'text': '</div>'
            })

    # Pending requests

    target_op = "addvgridowner"
    csrf_token = make_csrf_token(configuration, form_method, target_op,
                                 client_id, csrf_limit)
    helper = html_post_helper(
        "acceptvgridownerreq", "%s.py" % target_op, {
            'vgrid_name': vgrid_name,
            'cert_id': '__DYNAMIC__',
            'request_name': '__DYNAMIC__',
            csrf_field: csrf_token
        })
    output_objects.append({'object_type': 'html_form', 'text': helper})
    target_op = "addvgridmember"
    csrf_token = make_csrf_token(configuration, form_method, target_op,
                                 client_id, csrf_limit)
    helper = html_post_helper(
        "acceptvgridmemberreq", "%s.py" % target_op, {
            'vgrid_name': vgrid_name,
            'cert_id': '__DYNAMIC__',
            'request_name': '__DYNAMIC__',
            csrf_field: csrf_token
        })
    output_objects.append({'object_type': 'html_form', 'text': helper})
    target_op = "addvgridres"
    csrf_token = make_csrf_token(configuration, form_method, target_op,
                                 client_id, csrf_limit)
    helper = html_post_helper(
        "acceptvgridresourcereq", "%s.py" % target_op, {
            'vgrid_name': vgrid_name,
            'unique_resource_name': '__DYNAMIC__',
            'request_name': '__DYNAMIC__',
            csrf_field: csrf_token
        })
    output_objects.append({'object_type': 'html_form', 'text': helper})
    target_op = "rejectvgridreq"
    csrf_token = make_csrf_token(configuration, form_method, target_op,
                                 client_id, csrf_limit)
    helper = html_post_helper(
        "rejectvgridreq", "%s.py" % target_op, {
            'vgrid_name': vgrid_name,
            'request_name': '__DYNAMIC__',
            csrf_field: csrf_token
        })
    output_objects.append({'object_type': 'html_form', 'text': helper})

    request_dir = os.path.join(configuration.vgrid_home, vgrid_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 not req.get('request_type',
                       None) in ["vgridowner", "vgridmember", "vgridresource"]:
            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 = {"request_name": hexlify(req["request_name"])}
        accept_args, reject_args = {}, {}
        accept_args.update(shared_args)
        reject_args.update(shared_args)
        if req['request_type'] == "vgridresource":
            accept_args["unique_resource_name"] = req["entity"]
        else:
            accept_args["cert_id"] = req["entity"]

        request_item['acceptrequestlink'] = {
            'object_type':
            'link',
            'destination':
            "javascript: confirmDialog(%s, '%s', %s, %s);" %
            ("accept%(request_type)sreq" % req,
             "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);" %
            ("rejectvgridreq",
             "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
    })

    # VGrid Share links

    # Table columns to skip
    skip_list = [
        'editsharelink', 'delsharelink', 'invites', 'expire', 'single_file'
    ]

    # NOTE: Inheritance is a bit tricky for sharelinks because parent shares
    # only have relevance if they actually share a path that is a prefix of
    # vgrid_name.

    (share_status, share_list) = vgrid_sharelinks(vgrid_name, configuration)
    sharelinks = []
    if share_status:
        for share_dict in share_list:
            rel_path = share_dict['path'].strip(os.sep)
            parent_vgrids = vgrid_list_parents(vgrid_name, configuration)
            include_share = False
            # Direct sharelinks (careful not to greedy match A/B with A/BCD)
            if rel_path == vgrid_name or \
                    rel_path.startswith(vgrid_name+os.sep):
                include_share = True
            # Parent vgrid sharelinks that in effect also give access here
            for parent in parent_vgrids:
                if rel_path == parent:
                    include_share = True
            if include_share:
                share_item = build_sharelinkitem_object(
                    configuration, share_dict)
                sharelinks.append(share_item)
    else:
        logger.warning("failed to load vgrid sharelinks for %s: %s" %
                       (vgrid_name, share_list))

    output_objects.append({
        'object_type': 'sectionheader',
        'text': "Share Links"
    })
    output_objects.append({
        'object_type':
        'html_form',
        'text':
        '<p>Current share links in %s shared folder</p>' % vgrid_name
    })
    output_objects.append({
        'object_type': 'table_pager',
        'id_prefix': 'sharelinks_',
        'entry_name': 'share links',
        'default_entries': default_pager_entries
    })
    output_objects.append({
        'object_type': 'sharelinks',
        'sharelinks': sharelinks,
        'skip_list': skip_list
    })

    # VGrid settings

    output_objects.append({'object_type': 'sectionheader', 'text': "Settings"})

    (direct_status, direct_dict) = vgrid_settings(vgrid_name,
                                                  configuration,
                                                  recursive=False,
                                                  as_dict=True)
    if not direct_status or not direct_dict:
        direct_dict = {}
    (settings_status, settings_dict) = vgrid_settings(vgrid_name,
                                                      configuration,
                                                      recursive=True,
                                                      as_dict=True)
    if not settings_status or not settings_dict:
        settings_dict = {}
    form_method = 'post'
    csrf_limit = get_csrf_limit(configuration)
    # Always set these values
    settings_dict.update({
        'vgrid_name': vgrid_name,
        'vgrid_label': label,
        'owners': keyword_owners,
        'members': keyword_members,
        'all': keyword_all,
        'form_method': form_method,
        'csrf_field': csrf_field,
        'csrf_limit': csrf_limit
    })
    target_op = 'vgridsettings'
    csrf_token = make_csrf_token(configuration, form_method, target_op,
                                 client_id, csrf_limit)
    settings_dict.update({'target_op': target_op, 'csrf_token': csrf_token})

    settings_form = '''
    <form method="%(form_method)s" action="%(target_op)s.py">
        <fieldset>
            <legend>%(vgrid_label)s configuration</legend>
                <input type="hidden" name="%(csrf_field)s" value="%(csrf_token)s" />
                <input type="hidden" name="vgrid_name" value="%(vgrid_name)s" />
'''
    description = settings_dict.get('description', '')
    settings_form += '''
            <h4>Public description</h4>
                <textarea class="fillwidth padspace" name="description" rows=10
                    >%s</textarea>
''' % description
    settings_form += '<br/>'

    settings_form += '''<p>All visibility options below can be set to owners,
members or everyone and by default only owners can see participation. In effect
setting visibility to <em>members</em> means that owners and members can see
the corresponding participants. Similarly setting a visibility flag to
<em>everyone</em> means that all %s users can see the participants.</p>
''' % configuration.short_title
    visibility_options = [("Owners are visible to", "visible_owners"),
                          ("Members are visible to", "visible_members"),
                          ("Resources are visible to", "visible_resources")]
    for (title, field) in visibility_options:
        settings_form += '<h4>%s</h4>' % title
        if direct_dict.get(field, False):
            choices = _valid_visible + _reset_choice
        else:
            choices = _valid_visible + _keep_choice
        for (key, val) in choices:
            checked = ''
            if settings_dict.get(field, keyword_owners) == val:
                checked = "checked"
            settings_form += '''
            <input type="radio" name="%s" value="%s" %s/> %s
''' % (field, val, checked, key)
        settings_form += '<br/>'
    field = 'restrict_settings_adm'
    restrict_settings_adm = settings_dict.get(field,
                                              default_vgrid_settings_limit)
    if direct_dict.get(field, False):
        direct_note = _reset_note
    else:
        direct_note = _keep_note
    settings_form += '''
            <h4>Restrict Settings</h4>
            Restrict changing of these settings to only the first
            <input type="number" name="restrict_settings_adm" min=0 max=999
            minlength=1 maxlength=3 value=%d required />
            owners %s.
''' % (restrict_settings_adm, direct_note)
    settings_form += '<br/>'
    field = 'restrict_owners_adm'
    restrict_owners_adm = settings_dict.get(field,
                                            default_vgrid_settings_limit)
    if direct_dict.get(field, False):
        direct_note = _reset_note
    else:
        direct_note = _keep_note
    settings_form += '''
            <h4>Restrict Owner Administration</h4>
            Restrict administration of owners to only the first
            <input type="number" name="restrict_owners_adm" min=0 max=999
            minlength=1 maxlength=3 value=%d required />
            owners %s.
''' % (restrict_owners_adm, direct_note)
    settings_form += '<br/>'
    field = 'restrict_members_adm'
    restrict_members_adm = settings_dict.get(field,
                                             default_vgrid_settings_limit)
    if direct_dict.get(field, False):
        direct_note = _reset_note
    else:
        direct_note = _keep_note
    settings_form += '''
            <h4>Restrict Member Administration</h4>
            Restrict administration of members to only the first
            <input type="number" name="restrict_members_adm" min=0 max=999
            minlength=1 maxlength=3 value=%d required />
            owners %s.
''' % (restrict_members_adm, direct_note)
    settings_form += '<br/>'
    field = 'restrict_resources_adm'
    restrict_resources_adm = settings_dict.get(field,
                                               default_vgrid_settings_limit)
    if direct_dict.get(field, False):
        direct_note = _reset_note
    else:
        direct_note = _keep_note
    settings_form += '''
            <h4>Restrict Resource Administration</h4>
            Restrict administration of resources to only the first
            <input type="number" name="restrict_resources_adm" min=0 max=999
            minlength=1 maxlength=3 value=%d required />
            owners %s.
''' % (restrict_resources_adm, direct_note)
    settings_form += '<br/>'
    if vgrid_restrict_write_support(configuration):
        settings_form += '''<p>All write access options below can be set to
owners, members or none. By default only owners can write web pages while
owners and members can edit data in the shared folders. In effect setting write
access to <em>members</em> means that owners and members have full access.
Similarly setting a write access flag to <em>owners</em> means that only owners
can modify the data, while members can only read and use it. Finally setting a
write access flag to <em>none</em> means that neither owners nor members can
modify the data there, effectively making it read-only. Some options are not
yet supported and thus are disabled below.
</p>
'''
        writable_options = [
            ("Shared files write access", "write_shared_files",
             keyword_members),
            ("Private web page write access", "write_priv_web",
             keyword_owners),
            ("Public web page write access", "write_pub_web", keyword_owners),
        ]
    else:
        writable_options = []
    for (title, field, default) in writable_options:
        settings_form += '<h4>%s</h4>' % title
        if direct_dict.get(field, False):
            choices = _valid_write_access + _reset_choice
        else:
            choices = _valid_write_access + _keep_choice
        for (key, val) in choices:
            disabled = ''
            # TODO: remove these artifical limits once we support changing
            # TODO: also add check for vgrid web reshare in sharelink then
            if field == 'write_shared_files' and val == keyword_owners:
                disabled = 'disabled'
            elif field == 'write_priv_web' and val in [
                    keyword_members, keyword_none
            ]:
                disabled = 'disabled'
            elif field == 'write_pub_web' and val in [
                    keyword_members, keyword_none
            ]:
                disabled = 'disabled'
            checked = ''
            if settings_dict.get(field, default) == val:
                checked = "checked"
            settings_form += '''
            <input type="radio" name="%s" value="%s" %s %s /> %s
''' % (field, val, checked, disabled, key)
        settings_form += '<br/>'
    sharelink_options = [("Limit sharelink creation to", "create_sharelink")]
    for (title, field) in sharelink_options:
        settings_form += '<h4>%s</h4>' % title
        if direct_dict.get(field, False):
            choices = _valid_sharelink + _reset_choice
        else:
            choices = _valid_sharelink + _keep_choice
        for (key, val) in choices:
            checked = ''
            if settings_dict.get(field, keyword_owners) == val:
                checked = "checked"
            settings_form += '''
            <input type="radio" name="%s" value="%s" %s/> %s
''' % (field, val, checked, key)
        settings_form += '<br/>'
    field = 'request_recipients'
    request_recipients = settings_dict.get(field, default_vgrid_settings_limit)
    if direct_dict.get(field, False):
        direct_note = _reset_note
    else:
        direct_note = _keep_note
    settings_form += '''
            <h4>Request Recipients</h4>
            Notify only first
            <input type="number" name="request_recipients" min=0 max=999
            minlength=1 maxlength=3 value=%d required />
            owners about access requests %s.
''' % (request_recipients, direct_note)
    settings_form += '<br/>'

    bool_options = [
        ("Hidden", "hidden"),
    ]
    for (title, field) in bool_options:
        settings_form += '<h4>%s</h4>' % title
        if direct_dict.get(field, False):
            choices = _valid_bool + _reset_choice
        else:
            choices = _valid_bool + _keep_choice
        for (key, val) in choices:
            checked, inherit_note = '', ''
            if settings_dict.get(field, False) == val:
                checked = "checked"
            if direct_dict.get(field, False) != \
                    settings_dict.get(field, False):
                inherit_note = '''&nbsp;<span class="warningtext iconspace">
Forced by a parent %(vgrid_label)s. Please disable there first if you want to
change the value here.</span>''' % settings_dict
            settings_form += '''
            <input type="radio" name="%s" value="%s" %s /> %s
''' % (field, val, checked, key)
        settings_form += '%s<br/>' % inherit_note
    settings_form += '<br/>'

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

    # Checking/fixing of missing components

    output_objects.append({
        'object_type': 'sectionheader',
        'text': "Repair/Add Components"
    })
    target_op = 'updatevgrid'
    csrf_token = make_csrf_token(configuration, form_method, target_op,
                                 client_id, csrf_limit)
    settings_dict.update({'target_op': target_op, 'csrf_token': csrf_token})
    output_objects.append({
        'object_type':
        'html_form',
        'text':
        '''
      <form method="%(form_method)s" action="%(target_op)s.py">
        <input type="hidden" name="%(csrf_field)s" value="%(csrf_token)s" />
          <input type="hidden" name="vgrid_name" value="%(vgrid_name)s" />
          <input type="submit" value="Repair components" />
      </form>
''' % settings_dict
    })

    (owners_status, owners_direct) = vgrid_owners(vgrid_name, configuration,
                                                  False)
    if not owners_status:
        logger.error("failed to load owners for %s: %s" %
                     (vgrid_name, owners_direct))
        return (output_objects, returnvalues.SYSTEM_ERROR)
    (members_status, members_direct) = vgrid_members(vgrid_name, configuration,
                                                     False)
    if not members_status:
        logger.error("failed to load members for %s: %s" %
                     (vgrid_name, members_direct))
        return (output_objects, returnvalues.SYSTEM_ERROR)
    (resources_status,
     resources_direct) = vgrid_resources(vgrid_name, configuration, False)
    if not resources_status:
        logger.error("failed to load resources for %s: %s" %
                     (vgrid_name, resources_direct))
        return (output_objects, returnvalues.SYSTEM_ERROR)

    output_objects.append({
        'object_type': 'sectionheader',
        'text': "Delete %s " % vgrid_name
    })
    if len(owners_direct) > 1 or members_direct or resources_direct:
        output_objects.append({
            'object_type': 'html_form',
            'text': '''
To delete <b>%(vgrid)s</b> first remove all resources, members and owners
ending with yourself.
''' % {
                'vgrid': vgrid_name
            }
        })
    else:
        output_objects.append({
            'object_type': 'html_form',
            'text': '''
<p>As the last owner you can leave and delete <b>%(vgrid)s</b> including all
associated shared files and components.<br/>
</p>
<p class="warningtext">
You cannot undo such delete operations, so please use with great care!
</p>
''' % {
                'vgrid': vgrid_name
            }
        })
        target_op = "rmvgridowner"
        csrf_token = make_csrf_token(configuration, form_method, target_op,
                                     client_id, csrf_limit)
        js_name = 'rmlastvgridowner'
        helper = html_post_helper(
            js_name, '%s.py' % target_op, {
                'vgrid_name': vgrid_name,
                'cert_id': client_id,
                'flags': 'f',
                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 leave and delete %s?' % vgrid_name),
            'class':
            'removelink iconspace',
            'title':
            'Leave and delete %s' % vgrid_name,
            'text':
            'Leave and delete %s' % vgrid_name
        })

    # Spacing
    output_objects.append({
        'object_type':
        'html_form',
        'text':
        '''
            <div class="vertical-spacer"></div>
    '''
    })

    return (output_objects, returnvalues.OK)
Exemplo n.º 28
0
                    path_string += 'path=%s;' % parts[-1]

                job_obj['outputfileslink'] = {'object_type': 'link',
                                              'destination': 'ls.py?%s' % \
                                              path_string,
                                              'text': 'View output files'}

            form_method = 'post'
            csrf_limit = get_csrf_limit(configuration)
            target_op = 'resubmit'
            csrf_token = make_csrf_token(configuration, form_method, target_op,
                                         client_id, csrf_limit)
            js_name = 'resubmit%s' % hexlify(job_id)
            helper = html_post_helper(js_name, '%s.py' % target_op, {
                'job_id': job_id,
                csrf_field: csrf_token
            })
            output_objects.append({'object_type': 'html_form', 'text': helper})
            job_obj['resubmitlink'] = {
                'object_type': 'link',
                'destination': "javascript: %s();" % js_name,
                'text': 'Resubmit job'
            }

            target_op = 'jobaction'
            csrf_token = make_csrf_token(configuration, form_method, target_op,
                                         client_id, csrf_limit)
            js_name = 'freeze%s' % hexlify(job_id)
            helper = html_post_helper(js_name, '%s.py' % target_op, {
                'action': 'freeze',
                'job_id': job_id,
Exemplo n.º 29
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')
    label = "%s" % configuration.site_vgrid_label
    title_entry['text'] = "Remove %s Owner" % label
    output_objects.append({'object_type': 'header', 'text':
                           'Remove %s Owner' % label})
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
    )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    vgrid_name = accepted['vgrid_name'][-1]
    flags = ''.join(accepted['flags'])
    cert_id = accepted['cert_id'][-1]
    cert_dir = client_id_dir(cert_id)
    # inherited vgrid membership
    inherit_vgrid_member = False

    if not safe_handler(configuration, 'post', op_name, client_id,
                        get_csrf_limit(configuration), accepted):
        output_objects.append(
            {'object_type': 'error_text', 'text': '''Only accepting
CSRF-filtered POST requests to prevent unintended updates'''
             })
        return (output_objects, returnvalues.CLIENT_ERROR)

    # always allow owner to remove self
    if client_id != cert_id:

        user_map = get_full_user_map(configuration)
        user_dict = user_map.get(client_id, None)
        # Optional site-wide limitation of manage vgrid permission
        if not user_dict or \
                not vgrid_manage_allowed(configuration, user_dict):
            logger.warning("user %s is not allowed to manage vgrids!" %
                           client_id)
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 'Only privileged users can manage %ss' % label})
            return (output_objects, returnvalues.CLIENT_ERROR)

        # make sure vgrid settings allow this owner to edit other owners
        (allow_status, allow_msg) = allow_owners_adm(configuration, vgrid_name,
                                                     client_id)
        if not allow_status:
            output_objects.append({'object_type': 'error_text', 'text':
                                   allow_msg})
            return (output_objects, returnvalues.CLIENT_ERROR)

    # Validity of user and vgrid names is checked in this init function so
    # no need to worry about illegal directory traversal through variables

    (ret_val, msg, _) = \
        init_vgrid_script_add_rem(vgrid_name, client_id, cert_id,
                                  'owner', configuration)
    if not ret_val:
        output_objects.append({'object_type': 'error_text', 'text': msg})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # don't remove if not already an owner

    if not vgrid_is_owner(vgrid_name, cert_id, configuration):
        logger.warning('%s is not allowed to remove owner %s from %s' %
                       (client_id, cert_id, vgrid_name))
        output_objects.append({'object_type': 'error_text', 'text':
                               '%s is not an owner of %s or a parent %s.' %
                               (cert_id, vgrid_name, label)})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # we need the local owners file to detect inherited ownerships

    (owners_status, owners_direct) = vgrid_owners(vgrid_name, configuration,
                                                  False)
    (all_status, owners) = vgrid_owners(vgrid_name, configuration, True)
    if not owners_status or not all_status:
        logger.error('Error loading owners for %s: %s / %s'
                     % (vgrid_name, owners_direct, owners))
        output_objects.append(
            {'object_type': 'error_text', 'text':
             'An internal error occurred, error conditions have been logged.'})
        output_objects.append({'object_type': 'text', 'text': '''
         You can help us fix the problem by notifying the administrators
         via mail about what you wanted to do when the error happened.'''})
        return (output_objects, returnvalues.CLIENT_ERROR)

    logger.info('%s removing owner %s from %s' % (client_id, cert_id,
                                                  vgrid_name))

    # find out whether to just remove an owner or delete the whole thing.
    # ask about delete if last or no direct owners.

    if len(owners_direct) > 1:

        logger.debug('Removing %s, one of several owners, from %s.' %
                     (cert_id, vgrid_name))

        if not (cert_id in owners_direct):

            # the owner owns an upper vgrid, ownership is inherited
            # cannot remove, not last (inherited) owner

            logger.warning('Cannot delete: Inherited ownership.' +
                           '\n Owners: %s,\n Direct owners: %s.'
                           % (owners, owners_direct))
            output_objects.append({'object_type': 'error_text', 'text':
                                   '''%s is owner of a parent %s. 
Owner removal has to be performed at the topmost vgrid''' %
                                   (cert_id, label)})
            return (output_objects, returnvalues.CLIENT_ERROR)

        else:

            # Remove any tracker admin rights

            if configuration.trac_admin_path:
                public_tracker_dir = \
                    os.path.abspath(os.path.join(
                        configuration.vgrid_public_base, vgrid_name,
                        '.vgridtracker'))
                private_tracker_dir = \
                    os.path.abspath(os.path.join(
                        configuration.vgrid_private_base, vgrid_name,
                        '.vgridtracker'))
                vgrid_tracker_dir = \
                    os.path.abspath(os.path.join(
                        configuration.vgrid_files_home, vgrid_name,
                        '.vgridtracker'))
                for tracker_dir in [public_tracker_dir, private_tracker_dir,
                                    vgrid_tracker_dir]:
                    if not rm_tracker_admin(configuration, cert_id,
                                            vgrid_name, tracker_dir,
                                            output_objects):
                        return (output_objects, returnvalues.SYSTEM_ERROR)

            user_dir = os.path.abspath(os.path.join(configuration.user_home,
                                                    cert_dir)) + os.sep

            # Do not touch vgrid share if still a member of a parent vgrid

            if vgrid_is_member(vgrid_name, cert_id, configuration):
                # list is in top-down order
                parent_vgrids = vgrid_list_parents(vgrid_name, configuration)
                inherit_vgrid_member = vgrid_name
                for parent in parent_vgrids:
                    if vgrid_is_member(parent, cert_id, configuration,
                                       recursive=False):
                        inherit_vgrid_member = parent
                        break
                output_objects.append(
                    {'object_type': 'text', 'text':
                     '''NOTE: %s is still a member of parent %s %s.
Preserving access to corresponding %s.''' % (cert_id, label,
                                             inherit_vgrid_member, label)})
            else:
                (success, msg) = unlink_share(user_dir, vgrid_name)
                if not success:
                    logger.error('Could not remove share link: %s.' % msg)
                    output_objects.append({'object_type': 'error_text', 'text':
                                           'Could not remove share links: %s.'
                                           % msg})
                    return (output_objects, returnvalues.SYSTEM_ERROR)

            # unlink shared web folders

            (success, msg) = unlink_web_folders(user_dir, vgrid_name)
            if not success:
                logger.error('Could not remove web links: %s.' % msg)
                output_objects.append({'object_type': 'error_text', 'text':
                                       'Could not remove web links: %s.'
                                       % msg})
                return (output_objects, returnvalues.SYSTEM_ERROR)

            # remove user from saved owners list
            (rm_status, rm_msg) = vgrid_remove_owners(configuration, vgrid_name,
                                                      [cert_id])
            if not rm_status:
                output_objects.append({'object_type': 'error_text', 'text':
                                       '%s of owners of %s'
                                       % (rm_msg, vgrid_name)})
                return (output_objects, returnvalues.SYSTEM_ERROR)

            # Any parent vgrid membership is left untouched here as we only
            # force a normal refresh in unmap_inheritance
            unmap_inheritance(configuration, vgrid_name, cert_id)

            output_objects.append({'object_type': 'text', 'text':
                                   '%s successfully removed as owner of %s!'
                                   % (cert_id, vgrid_name)})
            output_objects.append({'object_type': 'link', 'destination':
                                   'adminvgrid.py?vgrid_name=%s' % vgrid_name, 'text':
                                   'Back to administration for %s' % vgrid_name})
            return (output_objects, returnvalues.OK)

    else:

        # no more direct owners - we try to remove this VGrid

        logger.debug('Leave %s from %s with no more direct owners: delete' %
                     (vgrid_name, cert_id))

        if not force(flags):
            output_objects.append({'object_type': 'text', 'text': '''
No more direct owners of %s - leaving will result in the %s getting
deleted. Please use either of the links below to confirm or cancel.
''' % (vgrid_name, label)})
            # Reuse csrf token from this request
            target_op = 'rmvgridowner'
            js_name = target_op
            csrf_token = accepted[csrf_field][-1]
            helper = html_post_helper(js_name, '%s.py' % target_op,
                                      {'vgrid_name': vgrid_name,
                                       'cert_id': cert_id, 'flags': 'f',
                                       csrf_field: csrf_token})
            output_objects.append({'object_type': 'html_form', 'text': helper})
            output_objects.append({'object_type': 'link', 'destination':
                                   "javascript: %s();" % js_name, 'class':
                                   'removelink iconspace', 'text':
                                   'Really leave and delete %s' % vgrid_name})
            output_objects.append({'object_type': 'text', 'text': ''})
            output_objects.append({'object_type': 'link', 'destination':
                                   'adminvgrid.py?vgrid_name=%s' % vgrid_name,
                                   'text': 'Back to administration for %s'
                                   % vgrid_name})
            return (output_objects, returnvalues.OK)

        # check if any resources participate or sub-vgrids depend on this one

        (list_status, subs) = vgrid_list_subvgrids(vgrid_name, configuration)

        if not list_status:
            logger.error('Error loading sub-vgrid for %s: %s)' % (vgrid_name,
                                                                  subs))
            output_objects.append({'object_type': 'error_text', 'text': '''
An internal error occurred, error conditions have been logged.'''})
            output_objects.append({'object_type': 'text', 'text': '''
You can help us fix the problem by notifying the administrators
via mail about what you wanted to do when the error happened.'''})
            return (output_objects, returnvalues.CLIENT_ERROR)

        if len(subs) > 0:
            logger.debug('Cannot delete: still has sub-vgrids: %s' % subs)
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 '%s has one or more child %ss and cannot be deleted.' %
                 (vgrid_name, label)})
            output_objects.append(
                {'object_type': 'text', 'text': '''To leave (and delete) %s
first remove all its children: %s.''' % (vgrid_name, ', '.join(subs))})
            return (output_objects, returnvalues.CLIENT_ERROR)

        # we consider the local members and resources here, not inherited ones

        (member_status, members_direct) = vgrid_members(vgrid_name,
                                                        configuration,
                                                        False)
        (resource_status, resources_direct) = vgrid_resources(vgrid_name,
                                                              configuration,
                                                              False)
        if not member_status or not resource_status:
            logger.warning('failed to load %s members or resources: %s %s'
                           % (vgrid_name, members_direct, resources_direct))
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 'could not load %s members or resources for %s.' %
                 (label, vgrid_name)})
            return (output_objects, returnvalues.SYSTEM_ERROR)
        if len(resources_direct) > 0:
            logger.debug('Cannot delete: still has direct resources %s.'
                         % resources_direct)
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 '%s still has resources and cannot be deleted.' % vgrid_name})
            output_objects.append({'object_type': 'text', 'text': '''
To leave (and delete) %s, first remove the participating resources.'''
                                   % vgrid_name})

            return (output_objects, returnvalues.CLIENT_ERROR)

        if len(members_direct) > 0:

            logger.debug('Cannot delete: still has direct members %s.'
                         % members_direct)
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 '%s still has members and cannot be deleted.' % vgrid_name})
            output_objects.append({'object_type': 'text', 'text': '''
To leave (and delete) %s, first remove all members.'''
                                   % vgrid_name})

            return (output_objects, returnvalues.CLIENT_ERROR)

        # Deleting write restricted VGrid is not allowed

        (load_status, saved_settings) = vgrid_settings(vgrid_name,
                                                       configuration,
                                                       recursive=True,
                                                       as_dict=True)
        if not load_status:
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 'failed to load saved %s settings' % vgrid_name})
            return (output_objects, returnvalues.SYSTEM_ERROR)

        if saved_settings.get('write_shared_files', keyword_members) != \
                keyword_members:
            logger.warning("%s can't delete vgrid %s - write limited!"
                           % (client_id, vgrid_name))
            output_objects.append(
                {'object_type': 'error_text', 'text': """You can't delete
write-restricted %ss - first remove any write restrictions for shared files
on the admin page and then try again.""" % label})
            return (output_objects, returnvalues.CLIENT_ERROR)

        # When reaching here, OK to remove the VGrid.
        #   if top-level: unlink, remove all files and directories,
        #   in all cases: remove configuration entry for the VGrid
        #   unlink and move new-style vgrid sub dir to parent

        logger.info('Deleting %s and all related data as requested by %s' %
                    (vgrid_name, cert_id))

        if (cert_id in owners_direct):

            # owner owns this vgrid, direct ownership

            logger.debug('%s looks like a top-level vgrid.' % vgrid_name)
            logger.debug('Deleting all related files.')

            user_dir = os.path.abspath(os.path.join(configuration.user_home,
                                                    cert_dir)) + os.sep
            (share_lnk, share_msg) = unlink_share(user_dir, vgrid_name)
            (web_lnk, web_msg) = unlink_web_folders(user_dir, vgrid_name)
            (files_act, files_msg) = abandon_vgrid_files(vgrid_name,
                                                         configuration)
        else:

            # owner owns some parent vgrid - ownership is only inherited

            logger.debug('%s looks like a sub-vgrid, ownership inherited.' %
                         vgrid_name)
            logger.debug('Only removing entry, leaving files in place.')
            share_lnk, share_msg = True, ''
            web_lnk, web_msg = True, ''
            (files_act, files_msg) = inherit_vgrid_files(vgrid_name,
                                                         configuration)

        (removed, entry_msg) = remove_vgrid_entry(vgrid_name, configuration)

        output_objects.append({'object_type': 'text', 'text':
                               '%s has been removed with last owner.'
                               % vgrid_name})

        output_objects.append({'object_type': 'link',
                               'destination': 'vgridman.py',
                               'text': 'Back to the overview.'})

        if not share_lnk or not web_lnk or not files_act or not removed:
            err = '\n'.join([share_msg, web_msg, files_msg, entry_msg])
            logger.error('Errors while removing %s:\n%s.' % (vgrid_name, err))

            output_objects.append({'object_type': 'error_text', 'text': '''
An internal error occurred, error conditions have been logged.'''})
            output_objects.append({'object_type': 'text', 'text': '''
You can help us fix the problem by notifying the administrators
via mail about what you wanted to do when the error happened.'''})
            return (output_objects, returnvalues.CLIENT_ERROR)

        else:

            # Remove vgrid from vgrid cache (after deleting all)
            unmap_vgrid(configuration, vgrid_name)
            return (output_objects, returnvalues.OK)
Exemplo n.º 30
0
def build_useritem_object_from_user_dict(configuration, visible_user_id, user_home, user_dict, allow_vgrids):
    """Build a user object based on input user_dict"""

    profile_specs = get_profile_specs()
    user_specs = get_settings_specs()
    user_item = {"object_type": "user_info", "user_id": visible_user_id, "fields": []}
    user_item["fields"].append(("Public user ID", visible_user_id))
    user_image = True
    public_image = user_dict[CONF].get("PUBLIC_IMAGE", [])
    if not public_image:
        user_image = False
        public_image = ["/images/anonymous.png"]
    img_html = '<div class="public_image">'
    for img_path in public_image:
        if user_image:
            img_data = inline_image(os.path.join(user_home, img_path))
        else:
            img_data = img_path
        img_html += '<img alt="portrait" src="%s">' % img_data
    img_html += "</div>"
    public_profile = user_dict[CONF].get("PUBLIC_PROFILE", [])
    if not public_profile:
        public_profile = ["No public information provided"]
    profile_html = '<div class="public_profile">'
    profile_html += "<br />".join(public_profile)
    profile_html += "</div>"
    public_html = '<div class="public_frame">\n%s\n%s\n</div>' % (profile_html, img_html)
    profile_html += '<div class="clear"></div>'
    user_item["fields"].append(("Public information", public_html))
    vgrids_allow_email = user_dict[CONF].get("VGRIDS_ALLOW_EMAIL", [])
    vgrids_allow_im = user_dict[CONF].get("VGRIDS_ALLOW_IM", [])
    hide_email = user_dict[CONF].get("HIDE_EMAIL_ADDRESS", True)
    hide_im = user_dict[CONF].get("HIDE_IM_ADDRESS", True)
    if hide_email:
        email_vgrids = []
    elif any_vgrid in vgrids_allow_email:
        email_vgrids = allow_vgrids
    else:
        email_vgrids = set(vgrids_allow_email).intersection(allow_vgrids)
    if hide_im:
        im_vgrids = []
    elif any_vgrid in vgrids_allow_im:
        im_vgrids = allow_vgrids
    else:
        im_vgrids = set(vgrids_allow_im).intersection(allow_vgrids)
    show_contexts = ["notify"]
    for (key, val) in user_specs:
        proto = key.lower()
        if not val["Context"] in show_contexts:
            continue
        saved = user_dict[CONF].get(key, None)
        if val["Type"] != "multiplestrings":
            saved = [saved]
        entry = ""
        if not email_vgrids and key == "EMAIL":
            show_address = "(email address hidden)"
        elif not im_vgrids and key != "EMAIL":
            show_address = "(IM address hidden)"
        else:
            show_address = ", ".join(saved)
        if saved:
            js_name = "send%s%s" % (proto, hexlify(visible_user_id))
            helper = html_post_helper(
                js_name,
                "sendrequestaction.py",
                {"cert_id": visible_user_id, "request_type": "plain", "protocol": proto, "request_text": ""},
            )
            entry += helper
            link = "send%slink" % proto
            link_obj = {
                "object_type": "link",
                "destination": "javascript: confirmDialog(%s, '%s', '%s');"
                % (js_name, "Send %s message to %s" % (proto, visible_user_id), "request_text"),
                "class": link,
                "title": "Send %s message to %s" % (proto, visible_user_id),
                "text": show_address,
            }
            entry += "%s " % html_link(link_obj)
        user_item["fields"].append((val["Title"], entry))
    return user_item