def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) vgrid_name = accepted['vgrid_name'][-1] if not vgrid_is_owner_or_member(vgrid_name, client_id, configuration): output_objects.append({'object_type': 'error_text', 'text': '''You must be an owner or member of %s vgrid to access the workflows.''' % vgrid_name}) return (output_objects, returnvalues.CLIENT_ERROR) title_entry = find_entry(output_objects, 'title') title_entry['text'] = '%s Workflows' \ % configuration.site_vgrid_label title_entry['style'] = themed_styles(configuration) title_entry['javascript'] = \ ''' <script type="text/javascript" src="/images/js/jquery.js"></script> <script type="text/javascript" src="/images/js/jquery.tablesorter.js"></script> <script type="text/javascript" src="/images/js/jquery.tablesorter.pager.js"></script> <script type="text/javascript" src="/images/js/jquery.tablesorter.widgets.js"></script> <script type="text/javascript" src="/images/js/jquery-ui.js"></script> <script type="text/javascript"> $(document).ready(function() { $("#logarea").scrollTop($("#logarea")[0].scrollHeight); // table initially sorted by 0 (last update / date) var sortOrder = [[0,1]]; // use image path for sorting if there is any inside var imgTitle = function(contents) { var key = $(contents).find("a").attr("class"); if (key == null) { key = $(contents).html(); } return key; } $("#workflowstable").tablesorter({widgets: ["zebra", "saveSort"], sortList:sortOrder, textExtraction: imgTitle }) .tablesorterPager({ container: $("#pager"), size: %s }); } ); </script> ''' \ % default_pager_entries output_objects.append({'object_type': 'html_form', 'text': ''' <div id="confirm_dialog" title="Confirm" style="background:#fff;"> <div id="confirm_text"><!-- filled by js --></div> <textarea cols="72" rows="10" id="confirm_input" style="display:none;"></textarea> </div> '''}) output_objects.append({'object_type': 'header', 'text': '%s Workflows for %s' % (configuration.site_vgrid_label, vgrid_name)}) logger.info('vgridworkflows %s' % vgrid_name) # Display active trigger jobs for this vgrid output_objects.append({'object_type': 'sectionheader', 'text': 'Active Trigger Jobs'}) html = '<table><thead><tr>' html += '<th>Job ID</th>' html += '<th>Rule</th>' html += '<th>Path</th>' html += '<th>Change</th>' html += '<th>Time</th>' html += '<th>Status</th>' html += '</tr></thead>' html += '<tbody>' trigger_job_dir = os.path.join(configuration.vgrid_home, os.path.join(vgrid_name, '.%s.jobs' % configuration.vgrid_triggers)) trigger_job_pending_dir = os.path.join(trigger_job_dir, 'pending_states') trigger_job_final_dir = os.path.join(trigger_job_dir, 'final_states' ) if makedirs_rec(trigger_job_pending_dir, logger) \ and makedirs_rec(trigger_job_final_dir, logger): abs_vgrid_dir = '%s/' \ % os.path.abspath(os.path.join(configuration.vgrid_files_home, vgrid_name)) for filename in os.listdir(trigger_job_pending_dir): trigger_job_filepath = \ os.path.join(trigger_job_pending_dir, filename) trigger_job = unpickle(trigger_job_filepath, logger) serverjob_filepath = \ os.path.join(configuration.mrsl_files_dir, os.path.join(client_id_dir(trigger_job['owner' ]), '%s.mRSL' % trigger_job['jobid'])) serverjob = unpickle(serverjob_filepath, logger) if serverjob: if serverjob['STATUS'] in pending_states: trigger_event = trigger_job['event'] trigger_rule = trigger_job['rule'] trigger_action = trigger_event['event_type'] trigger_time = time.ctime(trigger_event['time_stamp' ]) trigger_path = '%s %s' % (trigger_event['src_path' ].replace(abs_vgrid_dir, ''), trigger_event['dest_path' ].replace(abs_vgrid_dir, '')) html += \ '<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></td><td>%s</td>' \ % (trigger_job['jobid'], trigger_rule['rule_id' ], trigger_path, trigger_action, trigger_time, serverjob['STATUS']) elif serverjob['STATUS'] in final_states: src_path = os.path.join(trigger_job_pending_dir, filename) dest_path = os.path.join(trigger_job_final_dir, filename) move_file(src_path, dest_path, configuration) else: logger.error('Trigger job: %s, unknown state: %s' % (trigger_job['jobid'], serverjob['STATUS'])) html += '</tbody>' html += '</table>' output_objects.append({'object_type': 'html_form', 'text': html}) # Display active trigger jobs for this vgrid output_objects.append({'object_type': 'sectionheader', 'text': 'Trigger Log'}) log_content = read_trigger_log(configuration, vgrid_name) output_objects.append({'object_type': 'html_form', 'text': ''' <div class="form_container"> <textarea id="logarea" rows=10 readonly="readonly">%s</textarea> </div> ''' % log_content}) output_objects.append({'object_type': 'sectionheader', 'text': 'Manage Triggers'}) # Always run as rule creator to avoid users being able to act on behalf # of ANY other user using triggers (=exploit) extra_fields = [ ('path', None), ('match_dirs', ['False', 'True']), ('match_recursive', ['False', 'True']), ('changes', [keyword_all] + valid_trigger_changes), ('action', [keyword_auto] + valid_trigger_actions), ('arguments', None), ('run_as', client_id), ] # NOTE: we do NOT show saved template contents - see addvgridtriggers optional_fields = [('rate_limit', None), ('settle_time', None)] (status, oobjs) = vgrid_add_remove_table( client_id, vgrid_name, 'trigger', 'vgridtrigger', configuration, extra_fields, optional_fields, ) output_objects.extend(oobjs) if not status: return (output_objects, returnvalues.SYSTEM_ERROR) return (output_objects, returnvalues.OK)
def main(client_id, user_arguments_dict): """Main function used by front end""" (configuration, logger, output_objects, op_name) = \ initialize_main_variables(client_id, op_header=False) defaults = signature()[1] title_entry = find_entry(output_objects, 'title') label = "%s" % configuration.site_vgrid_label title_entry['text'] = '%s Workflows' % label # NOTE: Delay header entry here to include vgrid_name (validate_status, accepted) = validate_input_and_cert( user_arguments_dict, defaults, output_objects, client_id, configuration, allow_rejects=False, ) if not validate_status: return (accepted, returnvalues.CLIENT_ERROR) vgrid_name = accepted['vgrid_name'][-1] operation = accepted['operation'][-1] flags = ''.join(accepted['flags'][-1]) if not vgrid_is_owner_or_member(vgrid_name, client_id, configuration): output_objects.append({ 'object_type': 'error_text', 'text': '''You must be an owner or member of %s vgrid to access the workflows.''' % vgrid_name }) return (output_objects, returnvalues.CLIENT_ERROR) 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) if operation in show_operations: # jquery support for tablesorter (and unused confirmation dialog) # table initially sorted by 0 (last update / date) refresh_call = 'ajax_workflowjobs("%s", "%s")' % (vgrid_name, flags) table_spec = { 'table_id': 'workflowstable', 'sort_order': '[[0,1]]', 'refresh_call': refresh_call } (add_import, add_init, add_ready) = man_base_js(configuration, [table_spec]) if operation == "show": add_ready += '%s;' % refresh_call add_ready += ''' /* Init variables helper as foldable but closed and with individual heights */ $(".variables-accordion").accordion({ collapsible: true, active: false, heightStyle: "content" }); /* fix and reduce accordion spacing */ $(".ui-accordion-header").css("padding-top", 0) .css("padding-bottom", 0).css("margin", 0); /* NOTE: requires managers CSS fix for proper tab bar height */ $(".workflow-tabs").tabs(); $("#logarea").scrollTop($("#logarea")[0].scrollHeight); ''' 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': '%s Workflows for %s' % (label, vgrid_name) }) logger.info('vgridworkflows %s %s' % (vgrid_name, operation)) # Iterate through jobs and list details for each trigger_jobs = [] log_content = '' if operation in list_operations: trigger_job_dir = os.path.join( configuration.vgrid_home, os.path.join(vgrid_name, '.%s.jobs' % configuration.vgrid_triggers)) trigger_job_pending_dir = os.path.join(trigger_job_dir, 'pending_states') trigger_job_final_dir = os.path.join(trigger_job_dir, 'final_states') if makedirs_rec(trigger_job_pending_dir, configuration) \ and makedirs_rec(trigger_job_final_dir, configuration): abs_vgrid_dir = '%s/' \ % os.path.abspath(os.path.join(configuration.vgrid_files_home, vgrid_name)) for filename in os.listdir(trigger_job_pending_dir): trigger_job_filepath = \ os.path.join(trigger_job_pending_dir, filename) trigger_job = unpickle(trigger_job_filepath, logger) serverjob_filepath = \ os.path.join(configuration.mrsl_files_dir, os.path.join( client_id_dir(trigger_job['owner']), '%s.mRSL' % trigger_job['jobid'])) serverjob = unpickle(serverjob_filepath, logger) if serverjob: if serverjob['STATUS'] in pending_states: trigger_event = trigger_job['event'] trigger_rule = trigger_job['rule'] trigger_action = trigger_event['event_type'] trigger_time = time.ctime(trigger_event['time_stamp']) trigger_path = '%s %s' % \ (trigger_event['src_path'].replace( abs_vgrid_dir, ''), trigger_event['dest_path'].replace( abs_vgrid_dir, '')) job = { 'object_type': 'trigger_job', 'job_id': trigger_job['jobid'], 'rule_id': trigger_rule['rule_id'], 'path': trigger_path, 'action': trigger_action, 'time': trigger_time, 'status': serverjob['STATUS'] } if not job['rule_id'].startswith(img_trigger_prefix) \ or verbose(flags): trigger_jobs.append(job) elif serverjob['STATUS'] in final_states: src_path = os.path.join(trigger_job_pending_dir, filename) dest_path = os.path.join(trigger_job_final_dir, filename) move_file(src_path, dest_path, configuration) else: logger.error( 'Trigger job: %s, unknown state: %s' % (trigger_job['jobid'], serverjob['STATUS'])) log_content = read_trigger_log(configuration, vgrid_name, flags) if operation in show_operations: # Always run as rule creator to avoid users being able to act on behalf # of ANY other user using triggers (=exploit) extra_fields = [ ('path', None), ('match_dirs', ['False', 'True']), ('match_recursive', ['False', 'True']), ('changes', [keyword_all] + valid_trigger_changes), ('action', [keyword_auto] + valid_trigger_actions), ('arguments', None), ('run_as', client_id), ] # NOTE: we do NOT show saved template contents - see addvgridtriggers optional_fields = [('rate_limit', None), ('settle_time', None)] # Only include system triggers in verbose mode if verbose(flags): system_filter = [] else: system_filter = [('rule_id', '%s_.*' % img_trigger_prefix)] (init_status, oobjs) = vgrid_add_remove_table(client_id, vgrid_name, 'trigger', 'vgridtrigger', configuration, extra_fields + optional_fields, filter_items=system_filter) if not init_status: output_objects.append({ 'object_type': 'error_text', 'text': 'failed to load triggers: %s' % oobjs }) return (output_objects, returnvalues.SYSTEM_ERROR) # Generate variable helper values for a few concrete samples for help # text vars_html = '' dummy_rule = {'run_as': client_id, 'vgrid_name': vgrid_name} samples = [('input.txt', 'modified'), ('input/image42.raw', 'changed')] for (path, change) in samples: vgrid_path = os.path.join(vgrid_name, path) vars_html += "<b>Expanded variables when %s is %s:</b><br/>" % \ (vgrid_path, change) expanded = get_path_expand_map(vgrid_path, dummy_rule, change) for (key, val) in expanded.items(): vars_html += " %s: %s<br/>" % (key, val) commands_html = '' commands = get_usage_map(configuration) for usage in commands.values(): commands_html += " %s<br/>" % usage helper_html = """ <div class='variables-accordion'> <h4>Help on available trigger variable names and values</h4> <p> Triggers can use a number of helper variables on the form +TRIGGERXYZ+ to dynamically act on targets. Some of the values are bound to the rule owner the %s while the remaining ones are automatically expanded for the particular trigger target as shown in the following examples:<br/> %s </p> <h4>Help on available trigger commands and arguments</h4> <p> It is possible to set up trigger rules that basically run any operation with a side effect you could manually do on %s. I.e. like submitting/cancelling a job, creating/moving/deleting a file or directory and so on. When you select 'command' as the action for a trigger rule, you have the following commands at your disposal:<br/> %s </p> </div> """ % (label, vars_html, configuration.short_title, commands_html) # Make page with manage triggers tab and active jobs and log tab output_objects.append({ 'object_type': 'html_form', 'text': ''' <div id="wrap-tabs" class="workflow-tabs"> <ul> <li><a href="#manage-tab">Manage Triggers</a></li> <li><a href="#jobs-tab">Active Trigger Jobs</a></li> </ul> ''' }) # Display existing triggers and form to add new ones output_objects.append({ 'object_type': 'html_form', 'text': ''' <div id="manage-tab"> ''' }) output_objects.append({ 'object_type': 'sectionheader', 'text': 'Manage Triggers' }) output_objects.extend(oobjs) output_objects.append({ 'object_type': 'html_form', 'text': helper_html }) if configuration.site_enable_crontab: output_objects.append({ 'object_type': 'html_form', 'text': ''' <p>You can combine these workflows with the personal ''' }) output_objects.append({ 'object_type': 'link', 'destination': 'crontab.py', 'class': 'crontablink iconspace', 'text': 'schedule task' }) output_objects.append({ 'object_type': 'html_form', 'text': ''' facilities in case you want to trigger flows at given times rather than only in reaction to file system events.</p> ''' }) output_objects.append({ 'object_type': 'html_form', 'text': ''' </div> ''' }) # Display active trigger jobs and recent logs for this vgrid output_objects.append({ 'object_type': 'html_form', 'text': ''' <div id="jobs-tab"> ''' }) output_objects.append({ 'object_type': 'sectionheader', 'text': 'Active Trigger Jobs' }) output_objects.append({ 'object_type': 'table_pager', 'entry_name': 'job', 'default_entries': default_pager_entries }) output_objects.append({ 'object_type': 'trigger_job_list', 'trigger_jobs': trigger_jobs }) if operation in show_operations: output_objects.append({ 'object_type': 'sectionheader', 'text': 'Trigger Log' }) output_objects.append({ 'object_type': 'trigger_log', 'log_content': log_content }) if operation in show_operations: output_objects.append({ 'object_type': 'html_form', 'text': ''' </div> ''' }) output_objects.append({ 'object_type': 'html_form', 'text': ''' </div> ''' }) return (output_objects, returnvalues.OK)
return (False, 'Error writing frozen archive') logger.info("create_frozen_archive: move %s for %s" % \ (freeze_move, freeze_id)) for (real_source, rel_dst) in freeze_move: # Strip relative dir from move targets freeze_path = os.path.join(frozen_dir, os.path.basename(rel_dst)) frozen_files.append(os.path.basename(rel_dst)) logger.debug("create_frozen_archive: move %s" % freeze_path) if os.path.isdir(real_source): (status, msg) = move_rec(real_source, freeze_path, configuration) if not status: logger.error("create_frozen_archive: failed: %s" % msg) remove_rec(frozen_dir, configuration) return (False, 'Error writing frozen archive') else: (status, msg) = move_file(real_source, freeze_path, configuration) if not status: logger.error("create_frozen_archive: failed: %s" % msg) remove_rec(frozen_dir, configuration) return (False, 'Error writing frozen archive') logger.info("create_frozen_archive: save %s for %s" % \ ([i[0] for i in freeze_upload], freeze_id)) for (filename, contents) in freeze_upload: freeze_path = os.path.join(frozen_dir, filename) frozen_files.append(filename) logger.debug("create_frozen_archive: write %s" % freeze_path) if not write_file(contents, freeze_path, logger): logger.error("create_frozen_archive: failed: %s" % err) remove_rec(frozen_dir, configuration) return (False, 'Error writing frozen archive')