Beispiel #1
0
def flow_action_release(
    action_id: str = typer.Argument(...),
    flow_id: str = typer.Option(
        ...,
        help="The ID for the Flow which triggered the Action.",
        prompt=True,
    ),
    flow_scope: str = typer.Option(
        None,
        help="The scope this Flow uses to authenticate requests.",
        callback=url_validator_callback,
    ),
    output_format: OutputFormat = output_format_option,
    flows_endpoint: str = flows_env_var_option,
    verbose: bool = verbosity_option,
):
    """
    Remove execution history for a particular Flow definition's invocation.
    After this, no further information about the run can be accessed.
    """
    fc = create_flows_client(CLIENT_ID, flows_endpoint)
    method = functools.partial(fc.flow_action_release, flow_id, flow_scope,
                               action_id)
    RequestRunner(method, format=output_format, verbose=verbose,
                  watch=False).run_and_render()
def flow_display(
    flow_id: str = typer.Argument(...),
    output_format: FlowDisplayFormat = typer.Option(
        FlowDisplayFormat.json,
        "--format",
        "-f",
        help="Output display format.",
        case_sensitive=False,
        show_default=True,
    ),
    flows_endpoint: str = typer.Option(
        PROD_FLOWS_BASE_URL,
        hidden=True,
        callback=flows_endpoint_envvar_callback,
    ),
    verbose: bool = verbosity_option,
):
    """
    Display a deployed Flow. You must have either created the Flow or
    be present in the Flow's "visible_to" list to view it.
    """
    fc = create_flows_client(CLIENT_ID, flows_endpoint)
    flow_get = fc.get_flow(flow_id)

    _format_and_display_flow(flow_get, output_format, verbose=verbose)
def flow_action_cancel(
    action_id: str = typer.Argument(...),
    flow_id: str = typer.Option(
        ...,
        help="The ID for the Flow which triggered the Action.",
        prompt=True,
    ),
    flow_scope: str = typer.Option(
        None,
        help="The scope this Flow uses to authenticate requests.",
        callback=url_validator_callback,
    ),
    flows_endpoint: str = typer.Option(
        PROD_FLOWS_BASE_URL,
        hidden=True,
        callback=flows_endpoint_envvar_callback,
    ),
    verbose: bool = verbosity_option,
):
    """
    Cancel an active execution for a particular Flow definition's invocation.
    """
    fc = create_flows_client(CLIENT_ID, flows_endpoint)
    response = fc.flow_action_cancel(flow_id, flow_scope, action_id)
    format_and_echo(response, verbose=verbose)
Beispiel #4
0
def flow_action_update(
    action_id: str = typer.Argument(...),
    run_manager: Optional[List[str]] = typer.Option(
        None,
        help="A principal which may change the execution of the Run." +
        _principal_description + " [repeatable]",
        callback=principal_validator,
    ),
    run_monitor: Optional[List[str]] = typer.Option(
        None,
        help="A principal which may monitor the execution of the Run." +
        _principal_description + " [repeatable]",
        callback=principal_validator,
    ),
    flows_endpoint: str = flows_env_var_option,
    verbose: bool = verbosity_option,
    output_format: OutputFormat = output_format_option,
):
    """
    Update a Run on the Flows service
    """
    run_manager = run_manager if run_manager else None
    run_monitor = run_monitor if run_monitor else None
    fc = create_flows_client(CLIENT_ID, flows_endpoint, RUN_STATUS_SCOPE)
    RequestRunner(
        functools.partial(
            fc.flow_action_update,
            action_id,
            run_managers=run_manager,
            run_monitors=run_monitor,
        ),
        format=output_format,
        verbose=verbose,
    ).run_and_render()
Beispiel #5
0
def flow_action_status(
    action_id: str = typer.Argument(...),
    flow_id: str = typer.Option(
        None,
        help="The ID for the Flow which triggered the Action.",
    ),
    flow_scope: str = typer.Option(
        None,
        help="The scope this Flow uses to authenticate requests.",
        callback=url_validator_callback,
    ),
    flows_endpoint: str = flows_env_var_option,
    watch: bool = typer.Option(
        False,
        "--watch",
        "-w",
        help=
        "Continuously poll this Action until it reaches a completed state.",
        show_default=True,
    ),
    output_format: OutputFormat = output_format_option,
    verbose: bool = verbosity_option,
):
    """
    Display the status for a Flow definition's particular invocation.
    """
    fc = create_flows_client(CLIENT_ID, flows_endpoint)
    method = functools.partial(fc.flow_action_status, flow_id, flow_scope,
                               action_id)
    with live_content:
        RequestRunner(method,
                      format=output_format,
                      verbose=verbose,
                      watch=watch).run_and_render()
Beispiel #6
0
def flow_display(
    flow_id: str = typer.Argument("", show_default=False),
    flow_definition: str = typer.Option(
        "",
        help=
        ("JSON or YAML representation of the Flow to display. May be provided as a filename "
         "or a raw string representing a JSON object or YAML definition."),
        callback=input_validator,
        show_default=False,
    ),
    output_format: ImageOutputFormat = typer.Option(
        ImageOutputFormat.json,
        "--format",
        "-f",
        help="Output display format.",
        case_sensitive=False,
        show_default=True,
    ),
    flows_endpoint: str = flows_env_var_option,
):
    """
    Visualize a local or deployed Flow defintion. If providing a Flows's ID, You
    must have either created the Flow or be present in the Flow's "flow_viewers"
    list to view it.
    """
    if not flow_definition and not flow_id:
        raise typer.BadParameter(
            "Either FLOW_ID or --flow_definition should be set.")
    if flow_definition and flow_id:
        raise typer.BadParameter(
            "Only one of FLOW_ID or --flow_definition should be set.")

    fc = create_flows_client(CLIENT_ID, flows_endpoint)
    rr = RequestRunner(
        functools.partial(fc.get_flow, flow_id),
        format=output_format,
        verbose=False,
        watch=False,
    )

    if flow_id:
        result = rr.run()
        if result.is_api_error:
            rr.format = (output_format if output_format in {
                ImageOutputFormat.json, ImageOutputFormat.yaml
            } else ImageOutputFormat.json)
            rr.render(result)
            raise typer.Exit(1)
        else:
            flow_dict = result.data["definition"]
    else:
        flow_dict = process_input(flow_definition)

    if output_format in {ImageOutputFormat.json, ImageOutputFormat.yaml}:
        rr.render_as_result(flow_dict)
    else:
        output_format.visualize(flow_dict)
Beispiel #7
0
def retry_single(run_id, flow_id=None):
    if flow_id is None:
        flow_id = XPCSBoost().get_flow_id()
    fc = create_flows_client()

    resp = fc.flow_action_log(flow_id, fc.scope_for_flow(flow_id), run_id)
    run_input = resp['entries'][0]['details']['input']
    label = pathlib.Path(run_input['input']['hdf_file']).name[:62]
    return XPCSBoost().run_flow(flow_input=run_input, label=label)
Beispiel #8
0
def get_runs(flow_id=None):
    if flow_id is None:
        flow_id = XPCSBoost().get_flow_id()
    fc = create_flows_client()

    resp = fc.list_flow_runs(flow_id)
    runs = resp['actions']
    while resp['has_next_page']:
        resp = fc.list_flow_runs(flow_id, marker=resp['marker'])
        runs += resp['actions']
    return runs
Beispiel #9
0
def flow_get(
    flow_id: uuid.UUID = typer.Argument(..., help="A deployed Flow's ID"),
    output_format: OutputFormat = output_format_option,
    verbose: bool = verbosity_option,
    flows_endpoint: str = flows_env_var_option,
):
    """
    Get a Flow's definition as it exists on the Flows service.
    """
    fc = create_flows_client(CLIENT_ID, flows_endpoint)
    method = functools.partial(fc.get_flow, str(flow_id))
    RequestRunner(method, format=output_format,
                  verbose=verbose).run_and_render()
def flow_list(
    roles: List[FlowRole] = typer.Option(
        [FlowRole.created_by],
        "--role",
        "-r",
        help="Display Flows where you have the selected role. [repeatable]",
        case_sensitive=False,
        show_default=True,
    ),
    marker: str = typer.Option(
        None,
        "--marker",
        "-m",
        help="A pagination token for iterating through returned data.",
    ),
    per_page: int = typer.Option(
        None,
        "--per-page",
        "-p",
        help=
        "The page size to return. Only valid when used without providing a marker.",
        min=1,
        max=50,
    ),
    flows_endpoint: str = typer.Option(
        PROD_FLOWS_BASE_URL,
        hidden=True,
        callback=flows_endpoint_envvar_callback,
    ),
    verbose: bool = verbosity_option,
    output_format: FlowDisplayFormat = typer.Option(
        FlowDisplayFormat.json,
        "--format",
        "-f",
        help="Output display format.",
        case_sensitive=False,
        show_default=True,
    ),
):
    """
    List Flows for which you have access.
    """
    fc = create_flows_client(CLIENT_ID, flows_endpoint)
    flows = fc.list_flows(roles=[r.value for r in roles],
                          marker=marker,
                          per_page=per_page)

    _format_and_display_flow(flows, output_format, verbose=verbose)
Beispiel #11
0
def flow_delete(
    flow_id: str = typer.Argument(...),
    output_format: OutputFormat = output_format_option,
    flows_endpoint: str = flows_env_var_option,
    verbose: bool = verbosity_option,
):
    """
    Delete a Flow. You must be in the Flow's "flow_administrators" list.
    """
    fc = create_flows_client(CLIENT_ID, flows_endpoint)
    method = functools.partial(fc.delete_flow, flow_id)
    RequestRunner(
        method,
        format=output_format,
        verbose=verbose,
    ).run_and_render()
def flow_run(
    flow_id: str = typer.Argument(...),
    flow_input: str = typer.Option(
        None,
        help=
        ("JSON or YAML formatted input to the Flow. May be provided as a filename "
         "or a raw string."),
        callback=flow_input_validator,
    ),
    flow_scope: str = typer.Option(
        None,
        help="The scope this Flow uses to authenticate requests.",
        callback=url_validator_callback,
    ),
    flows_endpoint: str = typer.Option(
        PROD_FLOWS_BASE_URL,
        hidden=True,
        callback=flows_endpoint_envvar_callback,
    ),
    verbose: bool = verbosity_option,
    output_format: FlowDisplayFormat = typer.Option(
        FlowDisplayFormat.json,
        "--format",
        "-f",
        help="Output display format.",
        case_sensitive=False,
        show_default=True,
    ),
    input_format: InputFormat = typer.Option(
        InputFormat.json,
        "--input",
        "-i",
        help="Input format.",
        case_sensitive=False,
        show_default=True,
    ),
):
    """
    Run an instance of a Flow. The argument provides the initial state of the Flow.
    """
    fc = create_flows_client(CLIENT_ID, flows_endpoint)
    flow_input_dict = _process_flow_input(flow_input, input_format)

    response = fc.run_flow(flow_id, flow_scope, flow_input_dict)
    _format_and_display_flow(response, output_format, verbose=verbose)
def flow_delete(
    flow_id: str = typer.Argument(...),
    output_format: FlowDisplayFormat = typer.Option(
        FlowDisplayFormat.json,
        "--format",
        "-f",
        help="Output display format.",
        case_sensitive=False,
        show_default=True,
    ),
    flows_endpoint: str = typer.Option(
        PROD_FLOWS_BASE_URL,
        hidden=True,
        callback=flows_endpoint_envvar_callback,
    ),
    verbose: bool = verbosity_option,
):
    """
    Delete a Flow. You must either have created the Flow
    or be in the Flow's "administered_by" list.
    """
    fc = create_flows_client(CLIENT_ID, flows_endpoint)
    flow_del = fc.delete_flow(flow_id)
    _format_and_display_flow(flow_del, output_format, verbose=verbose)
def flow_deploy(
    title: str = typer.Option(..., help="The Flow's title.", prompt=True),
    definition: str = typer.Option(
        ...,
        help=
        ("JSON or YAML representation of the Flow to deploy. May be provided as a filename "
         "or a raw string representing a JSON object or YAML definition."),
        prompt=True,
        callback=input_validator_callback,
    ),
    subtitle: str = typer.Option(
        None,
        help="A subtitle for the Flow providing additional, brief description.",
    ),
    description: str = typer.Option(
        None, help="A long form description of the Flow's purpose or usage."),
    input_schema: str = typer.Option(
        None,
        help=
        ("A JSON or YAML representation of a JSON Schema which will be used to "
         "validate the input to the deployed Flow when it is run. "
         "If not provided, no validation will be performed on Flow input. "
         "May be provided as a filename or a raw string."),
        callback=input_validator_callback,
    ),
    keywords: List[str] = typer.Option(
        None,
        "--keyword",
        help=
        "A keyword which may categorize or help discover the Flow. [repeatable]",
    ),
    visible_to: List[str] = typer.Option(
        None,
        help=(
            "A principal which may see the existence of the deployed Flow. The "
            'special value of "public" may be used to control which users can '
            "discover this flow. [repeatable]"),
        callback=principal_or_public_validator,
    ),
    administered_by: List[str] = typer.Option(
        None,
        help="A principal which may update the deployed Flow. [repeatable]",
        callback=principal_validator,
    ),
    runnable_by: List[str] = typer.Option(
        None,
        help=
        ("A principal which may run an instance of the deployed Flow. The special "
         'value of "all_authenticated_users" may be used to control which users '
         "can invoke this flow. [repeatable]"),
        callback=principal_or_all_authenticated_users_validator,
    ),
    validate: bool = typer.Option(
        True,
        help=
        ("(EXPERIMENTAL) Perform rudimentary validation of the flow definition."
         ),
        case_sensitive=False,
        show_default=True,
    ),
    flows_endpoint: str = typer.Option(
        PROD_FLOWS_BASE_URL,
        hidden=True,
        callback=flows_endpoint_envvar_callback,
    ),
    verbose: bool = verbosity_option,
    input_format: InputFormat = typer.Option(
        InputFormat.json,
        "--input",
        "-i",
        help="Input format.",
        case_sensitive=False,
        show_default=True,
    ),
):
    """
    Deploy a new Flow.
    """
    fc = create_flows_client(CLIENT_ID, flows_endpoint)

    flow_dict = process_input(definition, input_format)
    input_schema_dict = process_input(input_schema, input_format,
                                      " for input schema")

    result = fc.deploy_flow(
        flow_dict,
        title,
        subtitle,
        description,
        keywords,
        visible_to,
        runnable_by,
        administered_by,
        input_schema_dict,
        validate_definition=validate,
    )

    # Match up output format with input format
    if input_format is InputFormat.json:
        format_and_echo(result, json.dumps, verbose=verbose)
    elif input_format is InputFormat.yaml:
        format_and_echo(result, yaml.dump, verbose=verbose)
def flow_action_log(
    action_id: str = typer.Argument(...),
    flow_id: str = typer.Option(
        ...,
        help="The ID for the Flow which triggered the Action.",
        prompt=True,
    ),
    flow_scope: str = typer.Option(
        None,
        help="The scope this Flow uses to authenticate requests.",
        callback=url_validator_callback,
    ),
    reverse: bool = typer.Option(
        # Defaulting to any boolean value will reverse output - so we use None
        None,
        "--reverse",
        help=
        "Display logs starting from most recent and proceeding in reverse chronological order",
    ),
    limit: int = typer.Option(
        None,
        help="Set a maximum number of events from the log to return",
        min=0,
        max=100,
    ),
    marker: str = typer.Option(
        None,
        "--marker",
        "-m",
        help="A pagination token for iterating through returned data.",
    ),
    per_page: int = typer.Option(
        None,
        "--per-page",
        "-p",
        help=
        "The page size to return. Only valid when used without providing a marker.",
        min=1,
        max=50,
    ),
    output_format: FlowDisplayFormat = typer.Option(
        FlowDisplayFormat.json,
        "--format",
        "-f",
        help="Output display format.",
        case_sensitive=False,
        show_default=True,
    ),
    flows_endpoint: str = typer.Option(
        PROD_FLOWS_BASE_URL,
        hidden=True,
        callback=flows_endpoint_envvar_callback,
    ),
    verbose: bool = verbosity_option,
):
    """
    Get a log of the steps executed by a Flow definition's invocation.
    """
    fc = create_flows_client(CLIENT_ID, flows_endpoint)
    resp = fc.flow_action_log(flow_id, flow_scope, action_id, limit, reverse,
                              marker, per_page)

    if verbose:
        display_http_details(resp)

    if output_format in (FlowDisplayFormat.json, FlowDisplayFormat.yaml):
        _format_and_display_flow(resp, output_format, verbose)
    elif output_format in (FlowDisplayFormat.graphviz,
                           FlowDisplayFormat.image):
        flow_def_resp = fc.get_flow(flow_id)
        flow_def = flow_def_resp.data["definition"]
        colors = state_colors_for_log(resp.data["entries"])
        graphviz_out = graphviz_format(flow_def, colors)

        if output_format == FlowDisplayFormat.graphviz:
            typer.echo(graphviz_out.source)
        else:
            graphviz_out.render("flows-output/graph", view=True, cleanup=True)
def flow_actions_list(
    flow_id: str = typer.Option(
        ...,
        help="The ID for the Flow which triggered the Action.",
        prompt=True,
    ),
    flow_scope: str = typer.Option(
        None,
        help="The scope this Flow uses to authenticate requests.",
        callback=url_validator_callback,
    ),
    roles: List[ActionRole] = typer.Option(
        None,
        "--role",
        help="Display Actions where you have the selected role. [repeatable]",
    ),
    statuses: List[ActionStatus] = typer.Option(
        None,
        "--status",
        help="Display Actions with the selected status. [repeatable]",
    ),
    marker: str = typer.Option(
        None,
        "--marker",
        "-m",
        help="A pagination token for iterating through returned data.",
    ),
    per_page: int = typer.Option(
        None,
        "--per-page",
        "-p",
        help=
        "The page size to return. Only valid when used without providing a marker.",
        min=1,
        max=50,
    ),
    flows_endpoint: str = typer.Option(
        PROD_FLOWS_BASE_URL,
        hidden=True,
        callback=flows_endpoint_envvar_callback,
    ),
    verbose: bool = verbosity_option,
):
    """
    List a Flow definition's discrete invocations.
    """
    fc = create_flows_client(CLIENT_ID, flows_endpoint)

    # This None check and check makes me unhappy but is necessary for mypy to
    # be happy with the enums. If we can figure out what defaults flows uses
    # for flow role/status queries, we can set those here and be done
    statuses_str, roles_str = None, None
    if statuses is not None:
        statuses_str = [s.value for s in statuses]
    if roles is not None:
        roles_str = [r.value for r in roles]

    action_list = fc.list_flow_actions(
        flow_id,
        flow_scope,
        statuses=statuses_str,
        roles=roles_str,
        marker=marker,
        per_page=per_page,
    )
    format_and_echo(action_list, verbose=verbose)
Beispiel #17
0
def flow_update(
    flow_id: str = typer.Argument(...),
    title: str = typer.Option(None, help="The Flow's title."),
    definition: str = typer.Option(
        None,
        help=
        ("JSON or YAML representation of the Flow to update. May be provided as a filename "
         "or a raw string."),
        callback=input_validator,
    ),
    subtitle: str = typer.Option(
        None,
        help="A subtitle for the Flow providing additional, brief description.",
    ),
    description: str = typer.Option(
        None, help="A long form description of the Flow's purpose or usage."),
    input_schema: str = typer.Option(
        None,
        help=
        ("A JSON or YAML representation of a JSON Schema which will be used to "
         "validate the input to the deployed Flow when it is run. "
         "If not provided, no validation will be performed on Flow input. "
         "May be provided as a filename or a raw string."),
        callback=input_validator,
    ),
    keywords: List[str] = typer.Option(
        None,
        "--keyword",
        help=
        "A keyword which may categorize or help discover the Flow. [repeatable]",
    ),
    flow_viewer: List[str] = typer.Option(
        None,
        help="A principal which may view this Flow. " +
        _principal_description +
        "The special value of 'public' may be used to "
        "indicate that any user can view this Flow. [repeatable]",
        callback=principal_or_public_validator,
    ),
    viewer: List[str] = typer.Option(None,
                                     callback=principal_or_public_validator,
                                     hidden=True),
    visible_to: List[str] = typer.Option(
        None, callback=principal_or_public_validator, hidden=True),
    flow_starter: List[str] = typer.Option(
        None,
        help="A principal which may run an instance of the deployed Flow. " +
        _principal_description + " The special value of "
        "'all_authenticated_users' may be used to indicate that any "
        "authenticated user can invoke this flow. [repeatable]",
        callback=principal_or_all_authenticated_users_validator,
    ),
    starter: List[str] = typer.Option(
        None,
        callback=principal_or_all_authenticated_users_validator,
        hidden=True),
    runnable_by: List[str] = typer.Option(
        None,
        callback=principal_or_all_authenticated_users_validator,
        hidden=True),
    flow_administrator: List[str] = typer.Option(
        None,
        help="A principal which may update the deployed Flow. " +
        _principal_description + "[repeatable]",
        callback=principal_validator,
    ),
    administrator: List[str] = typer.Option(None,
                                            callback=principal_validator,
                                            hidden=True),
    administered_by: List[str] = typer.Option(None,
                                              callback=principal_validator,
                                              hidden=True),
    assume_ownership: bool = typer.Option(
        False,
        "--assume-ownership",
        help=
        "Assume the ownership of the Flow. This can only be performed by user's "
        "in the flow_administrators role.",
    ),
    subscription_id: Optional[str] = typer.Option(
        None,
        help=
        "The Globus Subscription which will be used to make this flow managed.",
    ),
    validate: bool = typer.Option(
        True,
        help=
        ("(EXPERIMENTAL) Perform rudimentary validation of the flow definition."
         ),
        case_sensitive=False,
        show_default=True,
    ),
    flows_endpoint: str = flows_env_var_option,
    verbose: bool = verbosity_option,
    output_format: OutputFormat = output_format_option,
):
    """
    Update a Flow.
    """
    fc = create_flows_client(CLIENT_ID, flows_endpoint)
    flow_dict = process_input(definition)
    input_schema_dict = process_input(input_schema)

    method = functools.partial(
        fc.update_flow,
        flow_id,
        flow_dict,
        title,
        subtitle,
        description,
        keywords,
        flow_viewer,
        flow_starter,
        flow_administrator,
        subscription_id,
        input_schema_dict,
        validate_definition=validate,
        visible_to=visible_to,
        runnable_by=runnable_by,
        administered_by=administered_by,
    )
    RequestRunner(method, format=output_format,
                  verbose=verbose).run_and_render()
Beispiel #18
0
def flow_action_log(
    action_id: str = typer.Argument(...),
    flow_id: str = typer.Option(
        ...,
        help="The ID for the Flow which triggered the Action.",
        prompt=True,
    ),
    flow_scope: str = typer.Option(
        None,
        help="The scope this Flow uses to authenticate requests.",
        callback=url_validator_callback,
    ),
    reverse: bool = typer.Option(
        # Defaulting to any boolean value will reverse output - so we use None
        None,
        "--reverse",
        help=
        "Display logs starting from most recent and proceeding in reverse chronological order",
    ),
    limit: int = typer.Option(
        None,
        help="Set a maximum number of events from the log to return",
        min=0,
        max=100,
    ),
    marker: str = typer.Option(
        None,
        "--marker",
        "-m",
        help="A pagination token for iterating through returned data.",
    ),
    per_page: int = typer.Option(
        None,
        "--per-page",
        "-p",
        help=
        "The page size to return. Only valid when used without providing a marker.",
        min=1,
        max=50,
    ),
    output_format: RunLogOutputFormat = typer.Option(
        RunLogOutputFormat.table,
        "--format",
        "-f",
        help="Output display format.",
        case_sensitive=False,
        show_default=True,
    ),
    watch: bool = typer.Option(
        False,
        "--watch",
        "-w",
        help="Continuously poll this Action until it reaches a completed state. "
        "Using this option will report only the latest state available."
        "Only JSON and YAML output formats are supported.",
        show_default=True,
    ),
    flows_endpoint: str = flows_env_var_option,
    verbose: bool = verbosity_option,
):
    """
    Get a log of the steps executed by a Flow definition's invocation.
    """
    fc = create_flows_client(CLIENT_ID, flows_endpoint)
    method = functools.partial(
        fc.flow_action_log,
        flow_id,
        flow_scope,
        action_id,
        limit,
        reverse,
        marker,
        per_page,
    )
    rr = RequestRunner(
        method,
        format=output_format,
        verbose=verbose,
        watch=watch,
        fields=RunLogDisplayFields,
        detetector=LogCompletionDetetector,
    )
    with live_content:
        if output_format in {
                RunLogOutputFormat.json,
                RunLogOutputFormat.yaml,
                RunLogOutputFormat.table,
        }:
            rr.run_and_render()
        else:
            result = rr.run()
            if not result.is_api_error:
                flow_def = fc.get_flow(flow_id)
                output_format.visualize(result.result, flow_def)
            else:
                rr.format = RunLogOutputFormat.json
                rr.render(result)
Beispiel #19
0
def flow_list(
    roles: List[FlowRoleAllNames] = typer.Option(
        [FlowRole.flow_owner],
        "--role",
        "-r",
        help=
        ("Display Flows where you have at least the selected role. "
         "Precedence of roles is: flow_viewer, flow_starter, flow_administrator, "
         "flow_owner. Thus, by specifying, for example, flow_starter, all flows "
         "for which you hvae flow_starter, flow_administrator, or flow_owner roles "
         "will be displayed. Values visible_to, runnable_by, administered_by and "
         "created_by are deprecated. [repeatable use deprecated as the lowest "
         "precedence value provided will determine the flows displayed.]"),
        case_sensitive=False,
        show_default=True,
    ),
    marker: str = typer.Option(
        None,
        "--marker",
        "-m",
        help="A pagination token for iterating through returned data.",
    ),
    per_page: int = typer.Option(
        None,
        "--per-page",
        "-p",
        help=
        "The page size to return. Only valid when used without providing a marker.",
        min=1,
        max=50,
    ),
    flows_endpoint: str = flows_env_var_option,
    filters: Optional[List[str]] = typer.Option(
        None,
        "--filter",
        help="A filtering criteria in the form 'key=value' to apply to the "
        "resulting Flow listing. The key indicates the filter, the value "
        "indicates the pattern to match. Multiple patterns for a single key may "
        "be specified as a comma seperated string, the results for which will "
        "represent a logical OR. If multiple filters are applied, the returned "
        "data will be the result of a logical AND between them. [repeatable]",
    ),
    orderings: Optional[List[str]] = typer.Option(
        None,
        "--orderby",
        help=
        "An ordering criteria in the form 'key=value' to apply to the resulting "
        "Flow listing. The key indicates the field to order on, and the value is "
        "either ASC, for ascending order, or DESC, for descending order. The first "
        "ordering criteria will be used to sort the data, subsequent ordering criteria "
        "will further sort ties. [repeatable]",
    ),
    verbose: bool = verbosity_option,
    output_format: ListingOutputFormat = typer.Option(
        ListingOutputFormat.table,
        "--format",
        "-f",
        help="Output display format.",
        case_sensitive=False,
        show_default=True,
    ),
    watch: bool = typer.Option(
        False,
        "--watch",
        "-w",
        help="Continuously poll for new Flows.",
        show_default=True,
    ),
):
    """
    List Flows for which you have access.
    """
    parsed_filters = parse_query_options(filters)
    parsed_orderings = parse_query_options(orderings)
    role_param = make_role_param(roles)

    fc = create_flows_client(CLIENT_ID, flows_endpoint)
    method = functools.partial(
        fc.list_flows,
        marker=marker,
        per_page=per_page,
        filters=parsed_filters,
        orderings=parsed_orderings,
        **role_param,
    )
    with live_content:
        RequestRunner(
            method,
            format=output_format,
            verbose=verbose,
            watch=watch,
            fields=FlowListDisplayFields,
        ).run_and_render()
Beispiel #20
0
def flow_action_resume(
    action_id: str = typer.Argument(...),
    flow_id: str = typer.Option(
        ...,
        help="The ID for the Flow which triggered the Action.",
        prompt=True,
    ),
    flow_scope: str = typer.Option(
        None,
        help="The scope this Flow uses to authenticate requests.",
        callback=url_validator_callback,
    ),
    query_for_inactive_reason: bool = typer.Option(
        True,
        help=
        ("Should the Action first be queried to determine the reason for the "
         "resume, and prompt for additional consent if needed."),
    ),
    flows_endpoint: str = flows_env_var_option,
    output_format: OutputFormat = output_format_option,
    watch: bool = typer.Option(
        False,
        "--watch",
        "-w",
        help=
        "Continuously poll this Action until it reaches a completed state.",
        show_default=True,
    ),
    verbose: bool = verbosity_option,
):
    """Resume a Flow in the INACTIVE state. If query-for-inactive-reason is set, and the
    Flow Action is in an INACTIVE state due to requiring additional Consent, the required
    Consent will be determined and you may be prompted to allow Consent using the Globus
    Auth web interface.
    """
    fc = create_flows_client(CLIENT_ID, flows_endpoint)
    if query_for_inactive_reason:
        result = RequestRunner(
            functools.partial(fc.flow_action_status, flow_id, flow_scope,
                              action_id),
            format=output_format,
            verbose=verbose,
            watch=watch,
            run_once=True,
        ).run_and_render()
        if not result.is_api_error:
            body = result.data
            status = body.get("status")
            details = body.get("details", {})
            code = details.get("code")
            if status == "INACTIVE" and code == "ConsentRequired":
                flow_scope = details.get("required_scope")

    with live_content:
        result = RequestRunner(
            functools.partial(fc.flow_action_resume, flow_id, flow_scope,
                              action_id),
            format=output_format,
            verbose=verbose,
            watch=watch,
            run_once=True,
        ).run_and_render()
        if not result.is_api_error and watch:
            RequestRunner(
                functools.partial(fc.flow_action_status, flow_id, flow_scope,
                                  action_id),
                format=output_format,
                verbose=verbose,
                watch=watch,
            ).run_and_render()
Beispiel #21
0
def flow_deploy(
    title: str = typer.Option(..., help="The Flow's title.", prompt=True),
    definition: str = typer.Option(
        ...,
        help=
        ("JSON or YAML representation of the Flow to deploy. May be provided as a filename "
         "or a raw string representing a JSON object or YAML definition."),
        prompt=True,
        callback=input_validator,
    ),
    subtitle: str = typer.Option(
        None,
        help="A subtitle for the Flow providing additional, brief description.",
    ),
    description: str = typer.Option(
        None, help="A long form description of the Flow's purpose or usage."),
    input_schema: str = typer.Option(
        None,
        help=
        ("A JSON or YAML representation of a JSON Schema which will be used to "
         "validate the input to the deployed Flow when it is run. "
         "If not provided, no validation will be performed on Flow input. "
         "May be provided as a filename or a raw string."),
        callback=input_validator,
    ),
    keywords: List[str] = typer.Option(
        None,
        "--keyword",
        help=
        "A keyword which may categorize or help discover the Flow. [repeatable]",
    ),
    flow_viewer: List[str] = typer.Option(
        None,
        help=("A principal which may view this Flow. " +
              _principal_description +
              " The special value of 'public' may be used to "
              "indicate that any user can view this Flow. [repeatable]"),
        callback=principal_or_public_validator,
        hidden=False,
    ),
    # viewer and visible_to are aliases for the full flow_viewer
    viewer: List[str] = typer.Option(
        None,
        callback=principal_or_public_validator,
        hidden=True,
    ),
    visible_to: List[str] = typer.Option(
        None,
        callback=principal_or_public_validator,
        hidden=True,
    ),
    flow_starter: List[str] = typer.Option(
        None,
        help=
        ("A principal which may run an instance of the deployed Flow. " +
         _principal_description + "The special value of "
         "'all_authenticated_users' may be used to indicate that any authenticated user "
         "can invoke this flow. [repeatable]"),
        callback=principal_or_all_authenticated_users_validator,
    ),
    # starter and runnable_by are aliases for the full flow_starter
    starter: List[str] = typer.Option(
        None,
        callback=principal_or_all_authenticated_users_validator,
        hidden=True),
    runnable_by: List[str] = typer.Option(
        None,
        callback=principal_or_all_authenticated_users_validator,
        hidden=True),
    flow_administrator: List[str] = typer.Option(
        None,
        help=("A principal which may update the deployed Flow. " +
              _principal_description + "[repeatable]"),
        callback=principal_validator,
    ),
    # administrator and administered_by are aliases for the full flow_administrator
    administrator: List[str] = typer.Option(None,
                                            callback=principal_validator,
                                            hidden=True),
    administered_by: List[str] = typer.Option(None,
                                              callback=principal_validator,
                                              hidden=True),
    subscription_id: Optional[str] = typer.Option(
        None,
        help=
        "The Id of the Globus Subscription which will be used to make this flow managed.",
    ),
    validate: bool = typer.Option(
        True,
        help=
        ("(EXPERIMENTAL) Perform rudimentary validation of the flow definition."
         ),
        case_sensitive=False,
        show_default=True,
    ),
    flows_endpoint: str = flows_env_var_option,
    verbose: bool = verbosity_option,
    output_format: OutputFormat = output_format_option,
    dry_run: bool = typer.Option(
        False,
        "--dry-run",
        help=(
            "Do a dry run of deploying the flow to test your definition without"
            " actually making changes."),
    ),
):
    """
    Deploy a new Flow.
    """
    fc = create_flows_client(CLIENT_ID, flows_endpoint)
    flow_dict = process_input(definition)
    input_schema_dict = process_input(input_schema)

    method = functools.partial(
        fc.deploy_flow,
        flow_dict,
        title,
        subtitle,
        description,
        keywords,
        visible_to,
        runnable_by,
        administered_by,
        subscription_id,
        input_schema_dict,
        validate_definition=validate,
        dry_run=dry_run,
    )
    RequestRunner(method, format=output_format,
                  verbose=verbose).run_and_render()
Beispiel #22
0
def flow_actions_list(
    flow_id: Optional[str] = typer.Option(
        None,
        help=
        "The ID for the Flow which triggered the Action. If not present runs "
        "from all Flows will be displayed.",
    ),
    flow_scope: str = typer.Option(
        None,
        help="The scope this Flow uses to authenticate requests.",
        callback=url_validator_callback,
    ),
    roles: List[ActionRoleAllNames] = typer.Option(
        None,
        "--role",
        help=
        ("Display Actions/Runs where you have at least the selected role. "
         "Precedence of roles is: run_monitor, run_manager, "
         "run_owner. Thus, by specifying, for example, run_manager, all runs "
         "for which you hvae run_manager or run_owner roles "
         "will be displayed. [repeatable use deprecated as the lowest precedence "
         "value provided will determine the flows displayed.]"),
    ),
    statuses: List[ActionStatus] = typer.Option(
        [],
        "--status",
        help="Display Actions with the selected status. [repeatable]",
    ),
    marker: str = typer.Option(
        None,
        "--marker",
        "-m",
        help="A pagination token for iterating through returned data.",
    ),
    per_page: int = typer.Option(
        None,
        "--per-page",
        "-p",
        help=
        "The page size to return. Only valid when used without providing a marker.",
        min=1,
        max=50,
    ),
    filters: Optional[List[str]] = typer.Option(
        None,
        "--filter",
        help="A filtering criteria in the form 'key=value' to apply to the "
        "resulting Action listing. The key indicates the filter, the value "
        "indicates the pattern to match. Multiple patterns for a single key may "
        "be specified as a comma seperated string, the results for which will "
        "represent a logical OR. If multiple filters are applied, the returned "
        "data will be the result of a logical AND between them. [repeatable]",
    ),
    orderings: Optional[List[str]] = typer.Option(
        None,
        "--orderby",
        help=
        "An ordering criteria in the form 'key=value' to apply to the resulting "
        "Flow listing. The key indicates the field to order on, and the value is "
        "either ASC, for ascending order, or DESC, for descending order. The first "
        "ordering criteria will be used to sort the data, subsequent ordering criteria "
        "will further sort ties. [repeatable]",
    ),
    flows_endpoint: str = flows_env_var_option,
    verbose: bool = verbosity_option,
    watch: bool = typer.Option(
        False,
        "--watch",
        "-w",
        help="Continuously poll for new Actions.",
        show_default=True,
    ),
    output_format: ListingOutputFormat = typer.Option(
        ListingOutputFormat.table,
        "--format",
        "-f",
        help="Output display format.",
        case_sensitive=False,
        show_default=True,
    ),
):
    """
    List a Flow definition's discrete invocations.
    """
    parsed_filters = parse_query_options(filters)
    parsed_orderings = parse_query_options(orderings)
    statuses_str = [s.value for s in statuses]
    role_param = make_role_param(roles)

    fc = create_flows_client(CLIENT_ID, flows_endpoint)
    callable = functools.partial(
        fc.list_flow_actions,
        flow_id=flow_id,
        flow_scope=flow_scope,
        statuses=statuses_str,
        marker=marker,
        per_page=per_page,
        filters=parsed_filters,
        orderings=parsed_orderings,
        **role_param,
    )
    with live_content:
        RequestRunner(
            callable,
            format=output_format,
            verbose=verbose,
            watch=watch,
            fields=RunListDisplayFields,
        ).run_and_render()
Beispiel #23
0
def flow_run(
    flow_id: str = typer.Argument(...),
    flow_input: str = typer.Option(
        ...,
        help=
        ("JSON or YAML formatted input to the Flow. May be provided as a filename "
         "or a raw string."),
        callback=flow_input_validator,
    ),
    flow_scope: str = typer.Option(
        None,
        help="The scope this Flow uses to authenticate requests.",
        callback=url_validator_callback,
    ),
    run_manager: List[str] = typer.Option(
        None,
        help="A principal which may change the execution of the Flow instance. "
        + _principal_description + " [repeatable]",
        callback=principal_validator,
    ),
    manage_by: List[str] = typer.Option(None,
                                        callback=principal_validator,
                                        hidden=True),
    run_monitor: List[str] = typer.Option(
        None,
        help=
        "A principal which may monitor the execution of the Flow instance. " +
        _principal_description + " [repeatable]",
        callback=principal_validator,
    ),
    monitor_by: List[str] = typer.Option(None,
                                         callback=principal_validator,
                                         hidden=True),
    flows_endpoint: str = flows_env_var_option,
    verbose: bool = verbosity_option,
    output_format: OutputFormat = output_format_option,
    label: str = typer.Option(
        ...,
        "--label",
        "-l",
        help="Label to mark this run.",
    ),
    watch: bool = typer.Option(
        False,
        "--watch",
        "-w",
        help=
        "Continuously poll this Action until it reaches a completed state.",
        show_default=True,
    ),
    dry_run: bool = typer.Option(
        False,
        "--dry-run",
        help=
        ("Do a dry run with your input to this flow to test the input without"
         " actually running anything."),
    ),
):
    """
    Run an instance of a Flow. The argument provides the initial state of the Flow.
    You must be in the Flow's "flow_starters" list.
    """
    fc = create_flows_client(CLIENT_ID, flows_endpoint)
    flow_input_dict = process_input(flow_input)
    method = functools.partial(
        fc.run_flow,
        flow_id,
        flow_scope,
        flow_input_dict,
        run_monitors=run_monitor,
        run_managers=run_manager,
        label=label,
        dry_run=dry_run,
        monitor_by=monitor_by,
        manage_by=manage_by,
    )
    with live_content:
        result = RequestRunner(
            method,
            format=output_format,
            verbose=verbose,
            watch=watch,
            run_once=True,
        ).run_and_render()

        if not result.is_api_error and watch:
            action_id = result.data.get("action_id")
            method = functools.partial(fc.flow_action_status, flow_id,
                                       flow_scope, action_id)
            RequestRunner(
                method,
                format=output_format,
                verbose=verbose,
                watch=watch,
                run_once=False,
            ).run_and_render()