Exemplo n.º 1
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    defaults = signature()[1]
    title_entry = find_entry(output_objects, 'title')
    label = "%s" % configuration.site_vgrid_label
    title_entry['text'] = "Remove %s Resource" % label
    output_objects.append({
        'object_type': 'header',
        'text': 'Remove %s Resource' % 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]
    unique_resource_name = accepted['unique_resource_name'][-1].lower()

    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)

    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 resources

    (allow_status, allow_msg) = allow_resources_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, ret_variables) = \
        init_vgrid_script_add_rem(vgrid_name, client_id,
                                  unique_resource_name, 'resource',
                                  configuration)
    if not ret_val:
        output_objects.append({'object_type': 'error_text', 'text': msg})
        return (output_objects, returnvalues.CLIENT_ERROR)
    elif msg:

        # In case of warnings, msg is non-empty while ret_val remains True

        output_objects.append({'object_type': 'warning', 'text': msg})

    if not vgrid_is_owner(vgrid_name, client_id, configuration):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '''You must be an owner of the %s to
remove a resource!''' % label
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    # don't remove if not a participant

    if not vgrid_is_resource(vgrid_name, unique_resource_name, configuration):
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '%s is not a resource in %s or a parent %s.' %
            (unique_resource_name, vgrid_name, label)
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    # remove

    (rm_status, rm_msg) = vgrid_remove_resources(configuration, vgrid_name,
                                                 [unique_resource_name])
    if not rm_status:
        output_objects.append({'object_type': 'error_text', 'text': rm_msg})
        output_objects.append({
            'object_type': 'error_text',
            'text': '''%(res_name)s might be listed as a resource
of this %(vgrid_label)s because it is a resource of a parent %(vgrid_label)s.
Removal must be performed from the most significant %(vgrid_label)s possible.
''' % {
                'res_name': unique_resource_name,
                'vgrid_label': label
            }
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)

    output_objects.append({
        'object_type':
        'text',
        'text':
        'Resource %s successfully removed from %s %s!' %
        (unique_resource_name, vgrid_name, label)
    })
    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)
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')
    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.º 3
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    defaults = signature()[1]
    title_entry = find_entry(output_objects, 'title')
    label = "%s" % configuration.site_vgrid_label
    title_entry['text'] = "Add %s Member" % label
    output_objects.append({'object_type': 'header', 'text':
                           'Add %s Member(s)' % label})
    status = returnvalues.OK
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
    )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    vgrid_name = accepted['vgrid_name'][-1].strip()
    cert_id_list = accepted['cert_id']
    request_name = unhexlify(accepted['request_name'][-1])
    rank_list = accepted['rank'] + ['' for _ in cert_id_list]

    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)

    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 members

    (allow_status, allow_msg) = allow_members_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)

    cert_id_added = []
    for (cert_id, rank_str) in zip(cert_id_list, rank_list):
        cert_id = cert_id.strip()
        cert_dir = client_id_dir(cert_id)
        try:
            rank = int(rank_str)
        except ValueError:
            rank = None

        # Allow openid alias as subject if openid with alias is enabled
        if configuration.user_openid_providers and configuration.user_openid_alias:
            cert_id = expand_openid_alias(cert_id, configuration)

        # 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,
                                      'member', configuration)
        if not ret_val:
            output_objects.append({'object_type': 'error_text', 'text':
                                   msg})
            status = returnvalues.CLIENT_ERROR
            continue

        # don't add if already an owner

        if vgrid_is_owner(vgrid_name, cert_id, configuration):
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 '%s is already an owner of %s or a parent %s.' %
                 (cert_id, vgrid_name, label)})
            status = returnvalues.CLIENT_ERROR
            continue

        # don't add if already a member unless rank is given

        if rank is None and vgrid_is_member(vgrid_name, cert_id, configuration):
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 '''%s is already a member of %s or a parent %s. Please remove
    the person first and then try this operation again.''' %
                 (cert_id, vgrid_name, label)
                 })
            status = returnvalues.CLIENT_ERROR
            continue

        # owner or member of subvgrid?

        (list_status, subvgrids) = vgrid_list_subvgrids(vgrid_name,
                                                        configuration)
        if not list_status:
            output_objects.append({'object_type': 'error_text', 'text':
                                   'Error getting list of sub%ss: %s' %
                                   (label, subvgrids)})
            status = returnvalues.SYSTEM_ERROR
            continue

        # TODO: we DO allow ownership of sub vgrids with parent membership so we
        # should support the (cumbersome) relinking of vgrid shares here. Leave it
        # to user to do it manually for now with temporary removal of ownership

        skip_entity = False
        for subvgrid in subvgrids:
            if vgrid_is_owner(subvgrid, cert_id, configuration, recursive=False):
                output_objects.append(
                    {'object_type': 'error_text', 'text':
                     """%(cert_id)s is already an owner of a
sub-%(vgrid_label)s ('%(subvgrid)s'). While we DO support members being owners
of sub-%(vgrid_label)ss, we do not support adding parent %(vgrid_label)s
members at the moment. Please (temporarily) remove the person as owner of all
sub-%(vgrid_label)ss first and then try this operation again.""" %
                     {'cert_id': cert_id, 'subvgrid': subvgrid,
                      'vgrid_label': label}})
                status = returnvalues.CLIENT_ERROR
                skip_entity = True
                break
            if vgrid_is_member(subvgrid, cert_id, configuration, recursive=False):
                output_objects.append(
                    {'object_type': 'error_text', 'text':
                     """%s is already a member of a sub-%s ('%s'). Please
remove the person first and then try this operation again.""" %
                     (cert_id, label, subvgrid)})
                status = returnvalues.CLIENT_ERROR
                skip_entity = True
                break
        if skip_entity:
            continue

        # Check if only rank change was requested and apply if so

        if rank is not None:
            (add_status, add_msg) = vgrid_add_members(configuration,
                                                      vgrid_name,
                                                      [cert_id], rank=rank)
            if not add_status:
                output_objects.append(
                    {'object_type': 'error_text', 'text': add_msg})
                status = returnvalues.SYSTEM_ERROR
            else:
                output_objects.append({'object_type': 'text', 'text':
                                       'changed %s to member %d' % (cert_id,
                                                                    rank)})
            # No further action after rank change as everything else exists
            continue

        # Getting here means cert_id is neither owner or member of any parent or
        # sub-vgrids.

        # Please note that base_dir must end in slash to avoid access to other
        # vgrid dirs when own name is a prefix of another name

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

        # make sure all dirs can be created (that a file or directory with the same
        # name do not exist prior to adding the member)

        if os.path.exists(user_dir + vgrid_name):
            output_objects.append(
                {'object_type': 'error_text', 'text':
                 '''Could not add member, a file or directory in the home
directory called %s exists! (%s)''' % (vgrid_name, user_dir + vgrid_name)})
            status = returnvalues.CLIENT_ERROR
            continue

        # Add

        (add_status, add_msg) = vgrid_add_members(configuration, vgrid_name,
                                                  [cert_id])
        if not add_status:
            output_objects.append(
                {'object_type': 'error_text', 'text': add_msg})
            status = returnvalues.SYSTEM_ERROR
            continue

        vgrid_name_parts = vgrid_name.split('/')
        is_subvgrid = len(vgrid_name_parts) > 1

        if is_subvgrid:
            try:

                # vgrid_name = IMADA/STUD/BACH
                # vgrid_name_last_fragment = BACH

                vgrid_name_last_fragment = \
                    vgrid_name_parts[len(vgrid_name_parts)
                                     - 1].strip()

                # vgrid_name_without_last_fragment = IMADA/STUD/

                vgrid_name_without_last_fragment = \
                    ('/'.join(vgrid_name_parts[0:len(vgrid_name_parts)
                                               - 1]) + os.sep).strip()

                # create dirs if they do not exist

                dir1 = user_dir + vgrid_name_without_last_fragment
                if not os.path.isdir(dir1):
                    os.makedirs(dir1)
            except Exception, exc:

                # out of range? should not be possible due to is_subvgrid check

                output_objects.append(
                    {'object_type': 'error_text', 'text':
                     ('Could not create needed dirs on %s server! %s'
                      % (configuration.short_title, exc))})
                logger.error('%s when looking for dir %s.' % (exc, dir1))
                status = returnvalues.SYSTEM_ERROR
                continue

        # create symlink from users home directory to vgrid file directory

        link_src = os.path.abspath(configuration.vgrid_files_home + os.sep
                                   + vgrid_name) + os.sep
        link_dst = user_dir + vgrid_name

        # create symlink to vgrid files

        if not make_symlink(link_src, link_dst, logger):
            output_objects.append({'object_type': 'error_text', 'text':
                                   'Could not create link to %s files!' %
                                   label
                                   })
            logger.error('Could not create link to %s files! (%s -> %s)' %
                         (label, link_src, link_dst))
            status = returnvalues.SYSTEM_ERROR
            continue
        cert_id_added.append(cert_id)
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)
    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)

    output_objects.append({
        'object_type': 'header',
        'text': 'Cloud Instance Management'
    })

    user_map = get_full_user_map(configuration)
    user_dict = user_map.get(client_id, None)
    # Optional limitation of cload access vgrid 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)

    return_status = returnvalues.OK
    action = accepted['action'][-1]
    # NOTE: instance_X may be empty list - fall back to empty string
    instance_id = ([''] + accepted['instance_id'])[-1]
    instance_label = ([''] + accepted['instance_label'])[-1]
    instance_image = ([''] + accepted['instance_image'])[-1]
    accept_terms = (([''] + accepted['accept_terms'])[-1] in ('yes', 'on'))
    cloud_id = accepted['service'][-1]
    service = {
        k: v
        for options in configuration.cloud_services
        for k, v in options.items() if options['service_name'] == cloud_id
    }

    if not service:
        valid_services = [
            options['service_name'] for options in configuration.cloud_services
        ]
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '%s is not among the valid cloud services: %s' %
            (cloud_id, ', '.join(valid_services))
        })
        return (output_objects, returnvalues.CLIENT_ERROR)

    valid_service = valid_cloud_service(configuration, service)
    if not valid_service:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'The service %s appears to be misconfigured, '
            'please contact a system administrator about this issue' % cloud_id
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)

    service_title = service['service_title']
    if not action in valid_actions:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            '%s is not a valid action '
            'allowed actions include %s' % (action, ', '.join(valid_actions))
        })
        return (output_objects, returnvalues.CLIENT_ERROR)
    elif action in cloud_edit_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)

    cloud_flavor = service.get("service_flavor", "openstack")
    user_home_dir = os.path.join(configuration.user_home, client_dir)

    client_email = extract_field(client_id, 'email')
    if not client_email:
        logger.error("could not extract client email for %s!" % client_id)
        output_objects.append({
            'object_type': 'error_text',
            'text': "No client ID found - can't continue"
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)

    ssh_auth_msg = "Login requires your private key for your public key:"
    instance_missing_msg = "Found no '%s' instance at %s. Please contact a " \
                           + "site administrator if it should be there."

    _label = instance_label
    if instance_id and not _label:
        _, _label, _ = cloud_split_instance_id(configuration, client_id,
                                               instance_id)

    if "create" == action:
        if not accept_terms:
            logger.error("refusing create without accepting terms for %s!" %
                         client_id)
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                "You MUST accept the cloud user terms to create instances"
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

        # Load all instances and make sure none contains label in ID
        saved_instances = cloud_load_instance(configuration, client_id,
                                              cloud_id, keyword_all)
        for (saved_id, instance) in saved_instances.items():
            if instance_label == instance.get('INSTANCE_LABEL', saved_id):
                logger.error("Refused %s re-create %s cloud instance %s!" %
                             (client_id, cloud_id, instance_label))
                output_objects.append({
                    'object_type':
                    'error_text',
                    'text':
                    "You already have an instance with the label '%s'!" %
                    instance_label
                })
                return (output_objects, returnvalues.CLIENT_ERROR)

        max_instances = lookup_user_service_value(
            configuration, client_id, service, 'service_max_user_instances')
        max_user_instances = int(max_instances)
        # NOTE: a negative max value means unlimited but 0 or more is enforced
        if max_user_instances >= 0 and \
                len(saved_instances) >= max_user_instances:
            logger.error("Refused %s create additional %s cloud instances!" %
                         (client_id, cloud_id))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                "You already have the maximum allowed %s instances (%d)!" %
                (service_title, max_user_instances)
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

        if not instance_label:
            logger.error("Refused %s create unlabelled %s cloud instance!" %
                         (client_id, cloud_id))
            output_objects.append({
                'object_type': 'error_text',
                'text': "No instance label provided!"
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

        # 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 / allowed cloud images found!"
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

        if not instance_image:
            instance_image = allowed_images[0]
            logger.info("No image specified - using first for %s in %s: %s" %
                        (client_id, cloud_id, instance_image))

        image_id = None
        for (img_name, img_id, img_alias) in allowed_images:
            if instance_image == img_name:
                image_id = img_id
                break

        if not image_id:
            logger.error("No matching image ID found for %s in %s: %s" %
                         (client_id, cloud_id, instance_image))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                "No such  image found: %s" % instance_image
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

        # TODO: remove this direct key injection if we can delay it
        cloud_settings = load_cloud(client_id, configuration)
        raw_keys = cloud_settings.get('authkeys', '').split('\n')
        auth_keys = [i.split('#', 1)[0].strip() for i in raw_keys]
        auth_keys = [i for i in auth_keys if i]
        if not auth_keys:
            logger.error("No cloud pub keys setup for %s - refuse create" %
                         client_id)
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                """
You haven't provided any valid ssh pub key(s) for cloud instance login, which
is stricly required for all use. Please do so before you try again.
            """
            })
            output_objects.append({
                'object_type': 'link',
                'destination': 'setup.py?topic=cloud',
                'text': 'Open cloud setup',
                'class': 'cloudsetuplink iconspace',
                'title': 'open cloud setup',
                'target': '_blank'
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

        logger.debug("Continue create for %s with auth_keys: %s" %
                     (client_id, auth_keys))

        # Create a new internal keyset and session id
        (priv_key, pub_key) = generate_ssh_rsa_key_pair(encode_utf8=True)
        session_id = generate_random_ascii(session_id_bytes,
                                           charset='0123456789abcdef')
        # We make sure to create instance with a globally unique ID on the
        # cloud while only showing the requested instance_label to the user.
        instance_id = cloud_build_instance_id(configuration, client_email,
                                              instance_label, session_id)
        # TODO: make more fields flexible/conf
        cloud_dict = {
            'INSTANCE_ID': instance_id,
            'INSTANCE_LABEL': instance_label,
            'INSTANCE_IMAGE': instance_image,
            'IMAGE_ID': image_id,
            'AUTH_KEYS': auth_keys,
            'USER_CERT': client_id,
            'INSTANCE_PRIVATE_KEY': priv_key,
            'INSTANCE_PUBLIC_KEY': pub_key,
            # don't need fraction precision, also not all systems provide fraction
            # precision.
            'CREATED_TIMESTAMP': int(time.time()),
            # Init unset ssh address and leave for floating IP assigment below
            'INSTANCE_SSH_IP': '',
            'INSTANCE_SSH_PORT': 22,
        }
        (action_status,
         action_msg) = create_cloud_instance(configuration, client_id,
                                             cloud_id, cloud_flavor,
                                             instance_id, image_id, auth_keys)
        if not action_status:
            logger.error(
                "%s %s cloud instance %s for %s failed: %s" %
                (action, cloud_id, instance_id, client_id, action_msg))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Your %s instance %s at %s did not succeed: %s' %
                (action, instance_label, service_title, action_msg)
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)

        # On success the action_msg contains the assigned floating IP address
        instance_ssh_fqdn = action_msg
        cloud_dict['INSTANCE_SSH_IP'] = instance_ssh_fqdn
        if not cloud_save_instance(configuration, client_id, cloud_id,
                                   instance_id, cloud_dict):
            logger.error("save new %s cloud instance %s for %s failed" %
                         (cloud_id, instance_id, client_id))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Error saving your %s cloud instance setup' % service_title
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)

        output_objects.append({
            'object_type':
            'text',
            'text':
            "%s instance %s at %s: %s" %
            (action, instance_label, service_title, "success")
        })
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            _ssh_help(configuration, client_id, cloud_id, cloud_dict,
                      instance_id)
        })

    elif "delete" == action:
        saved_instance = cloud_load_instance(configuration, client_id,
                                             cloud_id, instance_id)
        if not saved_instance:
            logger.error("no saved %s cloud instance %s for %s to delete" %
                         (cloud_id, instance_id, client_id))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                instance_missing_msg % (_label, service_title)
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

        (action_status,
         action_msg) = delete_cloud_instance(configuration, client_id,
                                             cloud_id, cloud_flavor,
                                             instance_id)
        if not action_status:
            logger.error(
                "%s %s cloud instance %s for %s failed: %s" %
                (action, cloud_id, instance_id, client_id, action_msg))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Your %s instance %s at %s did not succeed: %s' %
                (action, _label, service_title, action_msg)
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)

        if not cloud_purge_instance(configuration, client_id, cloud_id,
                                    instance_id):
            logger.error("purge %s cloud instance %s for %s failed" %
                         (cloud_id, instance_id, client_id))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Error deleting your %s cloud instance setup' % service_title
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)

        output_objects.append({
            'object_type':
            'text',
            'text':
            "%s instance %s at %s: %s" %
            (action, _label, service_title, "success")
        })

    elif "status" == action:
        saved_instance = cloud_load_instance(configuration, client_id,
                                             cloud_id, instance_id)
        if not saved_instance:
            logger.error("no saved %s cloud instance %s for %s to query" %
                         (cloud_id, instance_id, client_id))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                instance_missing_msg % (_label, service_title)
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

        (action_status,
         action_msg) = status_of_cloud_instance(configuration, client_id,
                                                cloud_id, cloud_flavor,
                                                instance_id)
        if not action_status:
            logger.error(
                "%s %s cloud instance %s for %s failed: %s" %
                (action, cloud_id, instance_id, client_id, action_msg))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Your %s instance %s at %s did not succeed: %s' %
                (action, _label, service_title, action_msg)
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)

        output_objects.append({
            'object_type':
            'text',
            'text':
            "%s instance %s at %s: %s" %
            (action, _label, service_title, action_msg)
        })

        # Show instance access details if running
        if action_msg in ('ACTIVE', 'RUNNING'):
            # Only include web console if explicitly configured
            if configuration.user_cloud_console_access:
                (console_status, console_msg) = web_access_cloud_instance(
                    configuration, client_id, cloud_id, cloud_flavor,
                    instance_id)
                if not console_status:
                    logger.error(
                        "%s cloud instance %s console for %s failed: %s" % \
                        (cloud_id, instance_id, client_id, console_msg))
                    output_objects.append({
                        'object_type':
                        'error_text',
                        'text':
                        'Failed to get instance %s at %s console: %s' %
                        (_label, service_title, console_msg)
                    })
                    return (output_objects, returnvalues.SYSTEM_ERROR)
                logger.info("%s cloud instance %s console for %s: %s" %
                            (cloud_id, instance_id, client_id, console_msg))
                output_objects.append({
                    'object_type': 'link',
                    'destination': console_msg,
                    'text': 'Open web console',
                    'class': 'consolelink iconspace',
                    'title': 'open web console',
                    'target': '_blank'
                })
                output_objects.append({'object_type': 'text', 'text': ''})

            output_objects.append({
                'object_type':
                'html_form',
                'text':
                _ssh_help(configuration, client_id, cloud_id, saved_instance,
                          instance_id)
            })

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

    elif "start" == action:
        saved_instance = cloud_load_instance(configuration, client_id,
                                             cloud_id, instance_id)
        if not saved_instance:
            logger.error("no saved %s cloud instance %s for %s to start" %
                         (cloud_id, instance_id, client_id))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                instance_missing_msg % (_label, service_title)
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

        (action_status,
         action_msg) = start_cloud_instance(configuration, client_id, cloud_id,
                                            cloud_flavor, instance_id)
        if not action_status:
            logger.error(
                "%s %s cloud instance %s for %s failed: %s" %
                (action, cloud_id, instance_id, client_id, action_msg))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Your %s instance %s at %s did not succeed: %s' %
                (action, _label, service_title, action_msg)
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)

        output_objects.append({
            'object_type':
            'text',
            'text':
            "%s instance %s at %s: %s" %
            (action, _label, service_title, "success")
        })
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            _ssh_help(configuration, client_id, cloud_id, saved_instance,
                      instance_id)
        })

    elif action in ("softrestart", "hardrestart"):
        boot_strength = action.replace("restart", "").upper()
        saved_instance = cloud_load_instance(configuration, client_id,
                                             cloud_id, instance_id)
        if not saved_instance:
            logger.error("no saved %s cloud instance %s for %s to restart" %
                         (cloud_id, instance_id, client_id))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                instance_missing_msg % (_label, service_title)
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

        (action_status,
         action_msg) = restart_cloud_instance(configuration, client_id,
                                              cloud_id, cloud_flavor,
                                              instance_id, boot_strength)
        if not action_status:
            logger.error(
                "%s %s cloud instance %s for %s failed: %s" %
                (action, cloud_id, instance_id, client_id, action_msg))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Your %s instance %s at %s did not succeed: %s' %
                (action, _label, service_title, action_msg)
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)

        output_objects.append({
            'object_type':
            'text',
            'text':
            "%s instance %s at %s: %s" %
            (action, _label, service_title, "success")
        })
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            _ssh_help(configuration, client_id, cloud_id, saved_instance,
                      instance_id)
        })

    elif "stop" == action:
        saved_instance = cloud_load_instance(configuration, client_id,
                                             cloud_id, instance_id)
        if not saved_instance:
            logger.error("no saved %s cloud instance %s for %s to %s" %
                         (cloud_id, instance_id, client_id, action))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                instance_missing_msg % (_label, service_title)
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

        (action_status,
         action_msg) = stop_cloud_instance(configuration, client_id, cloud_id,
                                           cloud_flavor, instance_id)
        if not action_status:
            logger.error(
                "%s %s cloud instance %s for %s failed: %s" %
                (action, cloud_id, instance_id, client_id, action_msg))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Your %s instance %s at %s did not succeed: %s' %
                (action, _label, service_title, action_msg)
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)

        output_objects.append({
            'object_type':
            'text',
            'text':
            "%s instance %s at %s: %s" %
            (action, _label, service_title, "success")
        })

    elif "webaccess" == action:
        saved_instance = cloud_load_instance(configuration, client_id,
                                             cloud_id, instance_id)
        if not saved_instance:
            logger.error("no saved %s cloud instance %s for %s to query" %
                         (cloud_id, instance_id, client_id))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                instance_missing_msg % (_label, service_title)
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

        if not configuration.user_cloud_console_access:
            logger.error("web console not enabled in conf!")
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Site does not expose cloud web console!'
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

        (action_status,
         action_msg) = web_access_cloud_instance(configuration, client_id,
                                                 cloud_id, cloud_flavor,
                                                 instance_id)
        if not action_status:
            logger.error(
                "%s %s cloud instance %s for %s failed: %s" %
                (action, service_title, instance_id, client_id, action_msg))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Your %s instance %s at %s did not succeed: %s' %
                (action, _label, service_title, action_msg)
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)

        output_objects.append({
            'object_type':
            'text',
            'text':
            "%s instance %s at %s" % (action, _label, service_title)
        })
        output_objects.append({
            'object_type': 'link',
            'destination': action_msg,
            'text': 'Open web console',
            'class': 'consolelink iconspace',
            'title': 'open web console',
            'target': '_blank'
        })
        output_objects.append({'object_type': 'text', 'text': ''})
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            _ssh_help(configuration, client_id, cloud_id, saved_instance,
                      instance_id)
        })

    elif "updatekeys" == action:
        saved_instance = cloud_load_instance(configuration, client_id,
                                             cloud_id, instance_id)
        if not saved_instance:
            logger.error("no saved %s cloud instance %s for %s to update" %
                         (cloud_id, instance_id, client_id))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                instance_missing_msg % (_label, service_title)
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

        cloud_settings = load_cloud(client_id, configuration)
        auth_keys = cloud_settings.get('authkeys', '').split('\n')
        (action_status,
         action_msg) = update_cloud_instance_keys(configuration, client_id,
                                                  cloud_id, cloud_flavor,
                                                  instance_id, auth_keys)
        if not action_status:
            logger.error(
                "%s %s cloud instance %s for %s failed: %s" %
                (action, cloud_id, instance_id, client_id, action_msg))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Your %s instance %s at %s did not succeed: %s' %
                (action, _label, service_title, action_msg)
            })
            return (output_objects, returnvalues.SYSTEM_ERROR)

        output_objects.append({
            'object_type':
            'text',
            'text':
            "%s instance %s at %s: %s" %
            (action, _label, service_title, "success")
        })
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            _ssh_help(configuration, client_id, cloud_id, saved_instance,
                      instance_id)
        })
        output_objects.append({'object_type': 'text', 'text': ssh_auth_msg})
        for pub_key in auth_keys:
            output_objects.append({'object_type': 'text', 'text': pub_key})

    else:
        output_objects.append({
            'object_type': 'error_text',
            'text': 'Unknown action: %s' % action
        })
        return_status = returnvalues.CLIENT_ERROR

    output_objects.append({
        'object_type': 'link',
        'destination': 'cloud.py',
        'class': 'backlink iconspace',
        'title': 'Go back to cloud management',
        'text': 'Back to cloud management'
    })
    return (output_objects, return_status)
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]
    title_entry = find_entry(output_objects, 'title')
    label = "%s" % configuration.site_vgrid_label
    title_entry['text'] = "Remove %s Member" % label
    output_objects.append({
        'object_type': 'header',
        'text': 'Remove %s Member' % 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]
    cert_id = accepted['cert_id'][-1]
    cert_dir = client_id_dir(cert_id)

    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 member 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 members
        (allow_status, allow_msg) = allow_members_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,
                                  'member', 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 a member

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

    # owner of subvgrid?

    (list_status, subvgrids) = vgrid_list_subvgrids(vgrid_name, configuration)
    if not list_status:
        output_objects.append({
            'object_type':
            'error_text',
            'text':
            'Error getting list of sub%ss: %s' % (label, subvgrids)
        })
        return (output_objects, returnvalues.SYSTEM_ERROR)

    # TODO: we DO allow ownership of sub vgrids with parent membership so we
    # should support the (cumbersome) relinking of vgrid shares here. Leave it
    # to user to do it manually for now with temporary removal of ownership

    for subvgrid in subvgrids:
        if vgrid_is_owner(subvgrid, cert_id, configuration, recursive=False):
            output_objects.append({
                'object_type': 'error_text',
                'text':
                """%(cert_id)s is already an owner of a sub-%(vgrid_label)s
('%(subvgrid)s'). While we DO support members being owners of
sub-%(vgrid_label)ss, we do not support removing parent %(vgrid_label)s members
at the moment. Please (temporarily) remove the person as owner of all
sub-%(vgrid_label)ss first and then try this operation again.""" % {
                    'cert_id': cert_id,
                    'subvgrid': subvgrid,
                    'vgrid_label': label
                }
            })
            return (output_objects, returnvalues.CLIENT_ERROR)

    # Please note that base_dir must end in slash to avoid access to other
    # vgrid dirs when own name is a prefix of another name

    base_dir = os.path.abspath(
        os.path.join(configuration.vgrid_home, vgrid_name)) + os.sep

    # remove symlink from users home directory to vgrid directory

    # Please note that base_dir must end in slash to avoid access to other
    # user dirs when own name is a prefix of another user name

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

    dst = user_dir + vgrid_name
    try:
        os.remove(dst)
    except Exception, exc:

        # ouch, not good. Email admin?

        pass
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)
    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.º 7
0
def main(client_id, user_arguments_dict):
    """Main function used by front end"""

    (configuration, logger, output_objects, op_name) = \
        initialize_main_variables(client_id, op_header=False)
    defaults = signature()[1]
    title_entry = find_entry(output_objects, 'title')
    label = "%s" % configuration.site_vgrid_label
    title_entry['text'] = "Save %s Settings" % label
    output_objects.append(
        {'object_type': 'header', 'text': 'Save %s Settings' % 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)

    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)

    vgrid_name = accepted['vgrid_name'][-1].strip()

    new_settings = {'vgrid_name': vgrid_name}

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

    (ret_val, msg, ret_variables) = \
        init_vgrid_script_add_rem(vgrid_name, client_id,
                                  new_settings.items(), 'settings',
                                  configuration)
    if not ret_val:
        output_objects.append({'object_type': 'error_text', 'text': msg})
        return (output_objects, returnvalues.CLIENT_ERROR)
    elif msg:

        # In case of warnings, msg is non-empty while ret_val remains True

        output_objects.append({'object_type': 'warning', 'text': msg})

    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)

    # Check if this owner is allowed to change settings

    (allow_status, allow_msg) = allow_settings_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)

    # Build current settings, leaving out unset ones for default/inherit
    if not keyword_auto in accepted['description']:
        new_settings['description'] = '\n'.join(
            accepted['description']).strip()
    if not keyword_auto in accepted['visible_owners']:
        visible_owners = accepted['visible_owners'][-1]
        if visible_owners in _valid_visible:
            new_settings['visible_owners'] = visible_owners
        else:
            msg = "invalid visible_owners value: %s" % visible_owners
            logger.warning(msg)
            output_objects.append({'object_type': 'error_text', 'text': msg})
            return (output_objects, returnvalues.CLIENT_ERROR)
    if not keyword_auto in accepted['visible_members']:
        visible_members = accepted['visible_members'][-1]
        if visible_members in _valid_visible:
            new_settings['visible_members'] = visible_members
        else:
            msg = "invalid visible_members value: %s" % visible_members
            logger.warning(msg)
            output_objects.append({'object_type': 'error_text', 'text': msg})
            return (output_objects, returnvalues.CLIENT_ERROR)
    if not keyword_auto in accepted['visible_resources']:
        visible_resources = accepted['visible_resources'][-1]
        if visible_resources in _valid_visible:
            new_settings['visible_resources'] = visible_resources
        else:
            msg = "invalid visible_resources value: %s" % visible_resources
            logger.warning(msg)
            output_objects.append({'object_type': 'error_text', 'text': msg})
            return (output_objects, returnvalues.CLIENT_ERROR)
    if not keyword_auto in accepted['create_sharelink']:
        create_sharelink = accepted['create_sharelink'][-1]
        if create_sharelink in _valid_sharelink:
            new_settings['create_sharelink'] = create_sharelink
        else:
            msg = "invalid create_sharelink value: %s" % create_sharelink
            logger.warning(msg)
            output_objects.append({'object_type': 'error_text', 'text': msg})
            return (output_objects, returnvalues.CLIENT_ERROR)

    if not _keyword_auto_int in accepted['request_recipients']:
        try:
            request_recipients = accepted['request_recipients'][-1]
            request_recipients = int(request_recipients)
            new_settings['request_recipients'] = request_recipients
        except ValueError:
            msg = "invalid request_recipients value: %s" % request_recipients
            logger.warning(msg)
            output_objects.append({'object_type': 'error_text', 'text': msg})
            return (output_objects, returnvalues.CLIENT_ERROR)
    if not _keyword_auto_int in accepted['restrict_settings_adm']:
        try:
            restrict_settings_adm = accepted['restrict_settings_adm'][-1]
            restrict_settings_adm = int(restrict_settings_adm)
            new_settings['restrict_settings_adm'] = restrict_settings_adm
        except ValueError:
            msg = "invalid restrict_settings_adm value: %s" % \
                  restrict_settings_adm
            logger.warning(msg)
            output_objects.append({'object_type': 'error_text', 'text': msg})
            return (output_objects, returnvalues.CLIENT_ERROR)
    else:
        restrict_settings_adm = default_vgrid_settings_limit
    if not _keyword_auto_int in accepted['restrict_owners_adm']:
        try:
            restrict_owners_adm = accepted['restrict_owners_adm'][-1]
            restrict_owners_adm = int(restrict_owners_adm)
            new_settings['restrict_owners_adm'] = restrict_owners_adm
        except ValueError:
            msg = "invalid restrict_owners_adm value: %s" % restrict_owners_adm
            logger.warning(msg)
            output_objects.append({'object_type': 'error_text', 'text': msg})
            return (output_objects, returnvalues.CLIENT_ERROR)
    else:
        restrict_owners_adm = default_vgrid_settings_limit
    if not _keyword_auto_int in accepted['restrict_members_adm']:
        try:
            restrict_members_adm = accepted['restrict_members_adm'][-1]
            restrict_members_adm = int(restrict_members_adm)
            new_settings['restrict_members_adm'] = restrict_members_adm
        except ValueError:
            msg = "invalid restrict_members_adm value: %s" % \
                  restrict_members_adm
            logger.warning(msg)
            output_objects.append({'object_type': 'error_text', 'text': msg})
            return (output_objects, returnvalues.CLIENT_ERROR)
    if not _keyword_auto_int in accepted['restrict_resources_adm']:
        try:
            restrict_resources_adm = accepted['restrict_resources_adm'][-1]
            restrict_resources_adm = int(restrict_resources_adm)
            new_settings['restrict_resources_adm'] = restrict_resources_adm
        except ValueError:
            msg = "invalid restrict_resources_adm value: %s" % \
                  restrict_resources_adm
            logger.warning(msg)
            output_objects.append({'object_type': 'error_text', 'text': msg})
            return (output_objects, returnvalues.CLIENT_ERROR)
    if keyword_auto in accepted['write_shared_files']:
        write_shared_files = keyword_members
    else:
        write_shared_files = accepted['write_shared_files'][-1]
        if write_shared_files in _valid_write_access:
            new_settings['write_shared_files'] = write_shared_files
        else:
            msg = 'unknown write_shared_files value: %s' % write_shared_files
            output_objects.append({'object_type': 'error_text', 'text': msg})
            return (output_objects, returnvalues.CLIENT_ERROR)
    if keyword_auto in accepted['write_priv_web']:
        write_priv_web = keyword_owners
    else:
        write_priv_web = accepted['write_priv_web'][-1]
        if write_priv_web in _valid_write_access:
            new_settings['write_priv_web'] = write_priv_web
        else:
            msg = 'unknown write_priv_web value: %s' % write_priv_web
            output_objects.append({'object_type': 'error_text', 'text': msg})
            return (output_objects, returnvalues.CLIENT_ERROR)
    if keyword_auto in accepted['write_pub_web']:
        write_pub_web = keyword_owners
    else:
        write_pub_web = accepted['write_pub_web'][-1]
        if write_pub_web in _valid_write_access:
            new_settings['write_pub_web'] = write_pub_web
        else:
            msg = 'unknown write_pub_web value: %s' % write_pub_web
            output_objects.append({'object_type': 'error_text', 'text': msg})
            return (output_objects, returnvalues.CLIENT_ERROR)
    if not keyword_auto in accepted['hidden']:
        hidden = accepted['hidden'][-1]
        is_hidden = False
        if hidden.lower() in ("true", "1", "yes"):
            is_hidden = True
        new_settings['hidden'] = is_hidden

    if restrict_settings_adm > restrict_owners_adm:
        output_objects.append({'object_type': 'html_form', 'text': '''
<span class="warningtext">Warning: Restrict owner administration may still be
circumvented by some owners unless Restrict settings administration is set to
a lower or equal number.</span>'''})

    # TODO: remove this bail-out once we've implemented wider web write access
    if write_priv_web != keyword_owners or write_pub_web != keyword_owners:
        output_objects.append(
            {'object_type': 'error_text', 'text':
             """%s does not yet support changing write access to the
private and public web pages""" % configuration.short_title})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # Handle any write access limit changes first

    (load_old, old_settings) = vgrid_settings(vgrid_name, configuration,
                                              recursive=False, as_dict=True)
    if not load_old:
        output_objects.append(
            {'object_type': 'error_text', 'text':
             'failed to load saved %s settings' % vgrid_name})
        return (output_objects, returnvalues.SYSTEM_ERROR)
    old_write_shared = old_settings.get('write_shared_files', keyword_members)
    contact_text = """Please contact the %s admins if you then still get refused.
Then it is probably because they need to upgrade your %s %s to the new layout
format first.""" % (configuration.short_title, vgrid_name, label)

    # TODO: remove this bail-out once we've implemented owner-only write access
    if write_shared_files == keyword_owners:
        output_objects.append(
            {'object_type': 'error_text', 'text':
             """Owner-only write access is not supported yet"""})
        return (output_objects, returnvalues.CLIENT_ERROR)
    elif old_write_shared == write_shared_files:
        logger.debug("write shared status (%s) is unchanged" %
                     old_write_shared)
    else:
        if not vgrid_allow_restrict_write(vgrid_name, write_shared_files,
                                          configuration):
            if write_shared_files != keyword_members:
                # Refuse if any child vgrid is writable
                output_objects.append(
                    {'object_type': 'error_text', 'text': """Refused to tighten
write access for %s - layout or child prevents it! You need to make sure all
child %ss have at least as strict write access before you can proceed to
restrict %s. %s.""" % (vgrid_name, label, vgrid_name, contact_text)})
            else:
                # Refuse if parent vgrid restricts write
                output_objects.append(
                    {'object_type': 'error_text', 'text': """Refused to make
%s fully writable - layout or parent prevents it! You need to remove write
restrictions on all parent %ss before you can make %s writable. %s.""" %
                     (vgrid_name, label, vgrid_name, contact_text)})

            return (output_objects, returnvalues.CLIENT_ERROR)

        if not vgrid_restrict_write(vgrid_name, write_shared_files,
                                    configuration):
            if write_shared_files != keyword_members:
                output_objects.append(
                    {'object_type': 'error_text', 'text': """Failed to restrict
write to %s on %s shared files""" % (write_shared_files.lower(), vgrid_name)})
            else:
                output_objects.append(
                    {'object_type': 'error_text', 'text': """Failed to make %s
 fully writable""" % vgrid_name})

            return (output_objects, returnvalues.SYSTEM_ERROR)

    # format as list of tuples to fit usual form and then pickle

    (set_status, set_msg) = vgrid_set_settings(configuration, vgrid_name,
                                               new_settings.items())
    if not set_status:
        output_objects.append({'object_type': 'error_text', 'text': '%s'
                               % set_msg})
        return (output_objects, returnvalues.SYSTEM_ERROR)

    output_objects.append({'object_type': 'text', 'text':
                           'Settings saved for %s %s!' % (vgrid_name, label)})
    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)
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)
    defaults = signature()[1]
    title_entry = find_entry(output_objects, 'title')
    label = "%s" % configuration.site_vgrid_label
    title_entry['text'] = "Add %s Resource" % label
    output_objects.append({
        'object_type': 'header',
        'text': 'Add %s Resource(s)' % label
    })
    status = returnvalues.OK
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
    )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

    vgrid_name = accepted['vgrid_name'][-1].strip()
    res_id_list = accepted['unique_resource_name']
    request_name = unhexlify(accepted['request_name'][-1])
    rank_list = accepted['rank'] + ['' for _ in res_id_list]

    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)

    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 resources

    (allow_status, allow_msg) = allow_resources_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)

    res_id_added = []
    for (res_id, rank_str) in zip(res_id_list, rank_list):
        unique_resource_name = res_id.lower().strip()
        try:
            rank = int(rank_str)
        except ValueError:
            rank = None

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

        (ret_val, msg, ret_variables) = \
            init_vgrid_script_add_rem(vgrid_name, client_id,
                                      unique_resource_name, 'resource',
                                      configuration)
        if not ret_val:
            output_objects.append({'object_type': 'error_text', 'text': msg})
            status = returnvalues.CLIENT_ERROR
            continue
        elif msg:

            # In case of warnings, msg is non-empty while ret_val remains True

            output_objects.append({'object_type': 'warning', 'text': msg})

        # don't add if already in vgrid or parent vgrid unless rank is given

        if rank is None and vgrid_is_resource(vgrid_name, unique_resource_name,
                                              configuration):
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                '%s is already a resource in the %s' %
                (unique_resource_name, label)
            })
            status = returnvalues.CLIENT_ERROR
            continue

        # don't add if already in subvgrid

        (list_status,
         subvgrids) = vgrid_list_subvgrids(vgrid_name, configuration)
        if not list_status:
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Error getting list of sub%ss: %s' % (label, subvgrids)
            })
            status = returnvalues.SYSTEM_ERROR
            continue
        skip_entity = False
        for subvgrid in subvgrids:
            if vgrid_is_resource(subvgrid,
                                 unique_resource_name,
                                 configuration,
                                 recursive=False):
                output_objects.append({
                    'object_type': 'error_text',
                    'text': '''%(res_name)s is already in a
sub-%(vgrid_label)s (%(subvgrid)s). Please remove the resource from the
sub-%(vgrid_label)s and try again''' % {
                        'res_name': unique_resource_name,
                        'subvgrid': subvgrid,
                        'vgrid_label': label
                    }
                })
                status = returnvalues.CLIENT_ERROR
                skip_entity = True
                break
        if skip_entity:
            continue

        # Check if only rank change was requested and apply if so

        if rank is not None:
            (add_status, add_msg) = vgrid_add_resources(configuration,
                                                        vgrid_name,
                                                        [unique_resource_name],
                                                        rank=rank)
            if not add_status:
                output_objects.append({
                    'object_type': 'error_text',
                    'text': add_msg
                })
                status = returnvalues.SYSTEM_ERROR
            else:
                output_objects.append({
                    'object_type':
                    'text',
                    'text':
                    'changed %s to resource %d' % (res_id, rank)
                })
            # No further action after rank change as everything else exists
            continue

        # Getting here means res_id is neither resource of any parent or
        # sub-vgrids.

        # Please note that base_dir must end in slash to avoid access to other
        # vgrid dirs when own name is a prefix of another name

        base_dir = os.path.abspath(configuration.vgrid_home + os.sep +
                                   vgrid_name) + os.sep
        resources_file = base_dir + 'resources'

        # Add to list and pickle

        (add_status, add_msg) = vgrid_add_resources(configuration, vgrid_name,
                                                    [unique_resource_name])
        if not add_status:
            output_objects.append({
                'object_type': 'error_text',
                'text': '%s' % add_msg
            })
            status = returnvalues.SYSTEM_ERROR
            continue
        res_id_added.append(unique_resource_name)

    if request_name:
        request_dir = os.path.join(configuration.vgrid_home, vgrid_name)
        if not delete_access_request(configuration, request_dir, request_name):
            logger.error("failed to delete res request for %s in %s" %
                         (vgrid_name, request_name))
            output_objects.append({
                'object_type':
                'error_text',
                'text':
                'Failed to remove saved request for %s in %s!' %
                (vgrid_name, request_name)
            })

    if res_id_added:
        output_objects.append({
            'object_type':
            'html_form',
            'text':
            'New resource(s)<br />%s<br />successfully added to %s %s!'
            '' % ('<br />'.join(res_id_added), vgrid_name, label)
        })
        res_id_fields = ''
        for res_id in res_id_added:
            res_id_fields += """
<input type=hidden name=unique_resource_name value='%s' />""" % res_id

        form_method = 'post'
        csrf_limit = get_csrf_limit(configuration)
        fill_helpers = {
            'vgrid_name': vgrid_name,
            'unique_resource_name': unique_resource_name,
            'protocol': any_protocol,
            'short_title': configuration.short_title,
            'vgrid_label': label,
            'res_id_fields': res_id_fields,
            'form_method': form_method,
            'csrf_field': csrf_field,
            'csrf_limit': csrf_limit
        }
        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 type=hidden name=request_type value='vgridaccept' />
<input type=hidden name=vgrid_name value='%(vgrid_name)s' />
%(res_id_fields)s
<input type=hidden name=protocol value='%(protocol)s' />
<table>
<tr>
<td class='title'>Custom message to resource owners</td>
</tr><tr>
<td><textarea name=request_text cols=72 rows=10>
We have granted your %(unique_resource_name)s resource access to our
%(vgrid_name)s %(vgrid_label)s.
You can assign it to accept jobs from the %(vgrid_name)s %(vgrid_label)s from
your Resources page on %(short_title)s.

Regards, the %(vgrid_name)s %(vgrid_label)s owners
</textarea></td>
</tr>
<tr>
<td><input type='submit' value='Inform owners' /></td>
</tr>
</table>
</form>
<br />
""" % fill_helpers
        })

    output_objects.append({
        'object_type': 'link',
        'destination': 'adminvgrid.py?vgrid_name=%s' % vgrid_name,
        'text': 'Back to administration for %s' % vgrid_name
    })
    return (output_objects, returnvalues.OK)
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)
    client_dir = client_id_dir(client_id)
    defaults = signature()[1]
    (validate_status, accepted) = validate_input_and_cert(
        user_arguments_dict,
        defaults,
        output_objects,
        client_id,
        configuration,
        allow_rejects=False,
        )
    if not validate_status:
        return (accepted, returnvalues.CLIENT_ERROR)

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

    vgrid_name = accepted['vgrid_name'][-1].strip()

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

    # No owner check here so we need to specifically check for illegal
    # directory access

    reserved_names = (default_vgrid, any_vgrid, all_vgrids)
    if vgrid_name in reserved_names or \
           not valid_dir_input(configuration.vgrid_home, vgrid_name):
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'Illegal vgrid_name: %s' % vgrid_name})
        logger.warning("""createvgrid possible illegal directory access
attempt by '%s': vgrid_name '%s'""" % (client_id, vgrid_name))
        return (output_objects, returnvalues.CLIENT_ERROR)

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

    # Please note that base_dir must end in slash to avoid access to other
    # user dirs when own name is a prefix of another user name

    base_dir = os.path.abspath(os.path.join(configuration.vgrid_home,
                               vgrid_name)) + os.sep
    public_base_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_public_base,
                        vgrid_name)) + os.sep
    public_scm_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_public_base,
                        vgrid_name, '.vgridscm')) + os.sep
    public_tracker_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_public_base,
                        vgrid_name, '.vgridtracker')) + os.sep
    private_base_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_private_base,
                        vgrid_name)) + os.sep
    private_scm_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_private_base,
                        vgrid_name, '.vgridscm')) + os.sep
    private_tracker_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_private_base,
                        vgrid_name, '.vgridtracker')) + os.sep
    private_forum_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_private_base,
                        vgrid_name, '.vgridforum')) + os.sep
    vgrid_files_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_files_home,
                        vgrid_name)) + os.sep
    vgrid_scm_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_files_home,
                        vgrid_name, '.vgridscm')) + os.sep
    vgrid_tracker_dir = \
        os.path.abspath(os.path.join(configuration.vgrid_files_home,
                        vgrid_name, '.vgridtracker')) + os.sep

    # does vgrid exist?

    if os.path.isdir(base_dir):
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : '%s %s cannot be created because it already exists!'
             % (configuration.site_vgrid_label, vgrid_name)})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # verify that client is owner of imada or imada/topology if trying to
    # create imada/topology/test

    vgrid_name_list = vgrid_name.split('/')
    vgrid_name_list_length = len(vgrid_name_list)
    if vgrid_name_list_length <= 0:
        output_objects.append({'object_type': 'error_text', 'text'
                              : 'vgrid_name not specified?'})
        return (output_objects, returnvalues.SYSTEM_ERROR)
    elif vgrid_name_list_length == 1:

        # anyone can create base vgrid

        new_base_vgrid = True
    else:
        new_base_vgrid = False
        vgrid_name_without_last_fragment = \
            '/'.join(vgrid_name_list[0:vgrid_name_list_length - 1])
        parent_base = os.path.dirname(base_dir.rstrip(os.sep))
        if not os.path.isdir(parent_base):
            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : 'Parent %s %s does not exist!' % \
                 (configuration.site_vgrid_label,
                  vgrid_name_without_last_fragment)
                 })
            return (output_objects, returnvalues.CLIENT_ERROR)
        if not vgrid_is_owner(vgrid_name_without_last_fragment,
                              client_id, configuration):
            output_objects.append(
                {'object_type': 'error_text', 'text'
                 : 'You must own a parent %s to create a sub vgrid' % \
                 configuration.site_vgrid_label
                 })
            return (output_objects, returnvalues.CLIENT_ERROR)

    # make sure all dirs can be created (that a file or directory with the same
    # name do not exist prior to the vgrid creation)

    try_again_string = \
        """%s cannot be created, a file or directory exists with the same
name, please try again with a new name!""" % configuration.site_vgrid_label
    if os.path.exists(public_base_dir):
        output_objects.append({'object_type': 'error_text', 'text'
                              : try_again_string})
        return (output_objects, returnvalues.CLIENT_ERROR)

    if os.path.exists(private_base_dir):
        output_objects.append({'object_type': 'error_text', 'text'
                              : try_again_string})
        return (output_objects, returnvalues.CLIENT_ERROR)

    if os.path.exists(vgrid_files_dir):
        output_objects.append({'object_type': 'error_text', 'text'
                              : try_again_string})
        return (output_objects, returnvalues.CLIENT_ERROR)

    # create directory to store vgrid files

    try:
        os.mkdir(base_dir)
    except Exception, exc:
        output_objects.append(
            {'object_type': 'error_text', 'text'
             : """Could not create %(_label)s directory, remember to create
parent %(_label)s before creating a sub-%(_label)s.""" % \
             {'_label': configuration.site_vgrid_label}
             })
        return (output_objects, returnvalues.CLIENT_ERROR)
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)
    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.º 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)
    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)