Ejemplo n.º 1
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)
Ejemplo n.º 2
0
def flow_lint(
    definition: str = typer.Option(
        ...,
        help=
        ("JSON or YAML representation of the Flow to deploy. May be provided as a filename "
         "or a raw string."),
        prompt=True,
        callback=input_validator_callback,
    ),
    validate: bool = typer.Option(
        True,
        help=
        ("(EXPERIMENTAL) Perform rudimentary validation of the flow definition."
         ),
        case_sensitive=False,
        show_default=True,
    ),
    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,
    ),
):
    """
    Parse and validate a Flow definition by providing visual output.
    """
    flow_dict = process_input(definition, input_format)

    try:
        if validate:
            validate_flow_definition(flow_dict)
    except FlowValidationError as fve:
        typer.secho(str(fve), fg=typer.colors.RED)
        raise typer.Exit(code=1)

    graph = graphviz_format(flow_dict)
    if output_format is FlowDisplayFormat.json:
        format_and_echo(flow_dict)
    elif output_format is FlowDisplayFormat.yaml:
        format_and_echo(flow_dict, yaml.dump)
    elif output_format is FlowDisplayFormat.graphviz:
        typer.echo(graph.source)
    else:
        graph.render("flows-output/graph", view=True, cleanup=True)
Ejemplo n.º 3
0
def flow_lint(definition: str = typer.Option(
    ...,
    help=
    ("JSON or YAML representation of the Flow to deploy. May be provided as a filename "
     "or a raw string."),
    prompt=True,
    callback=input_validator,
), ):
    """
    Parse and validate a Flow definition by providing visual output.
    """
    flow_dict = process_input(definition)

    try:
        validate_flow_definition(flow_dict)
    except FlowValidationError as fve:
        typer.secho(str(fve), fg=typer.colors.RED)
        raise typer.Exit(code=1)

    typer.secho("No issues found in the Flow definition.",
                fg=typer.colors.GREEN)
Ejemplo n.º 4
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_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)
Ejemplo n.º 5
0
def action_run(
    action_url: str = typer.Option(
        ...,
        help="The url at which the target Action Provider is located.",
        prompt=True,
        callback=url_validator_callback,
    ),
    action_scope: str = typer.Option(
        None,
        help="The scope this Action Provider uses to authenticate requests.",
        callback=url_validator_callback,
    ),
    body: str = typer.Option(
        ...,
        "--body",
        "-b",
        help=
        ("The body to supply to the Action Provider. Can be a filename or raw "
         "JSON string."),
        prompt=True,
        callback=input_validator_callback,
    ),
    request_id: str = typer.Option(
        None,
        help=(
            "An identifier to associate with this Action invocation request"),
    ),
    manage_by: List[str] = typer.Option(
        None,
        help=
        "A principal which may change the execution of the Action. [repeatable]",
        callback=principal_validator,
    ),
    monitor_by: List[str] = typer.Option(
        None,
        help="A principal which may view the state of the Action. [repeatable]",
        callback=principal_validator,
    ),
    verbose: bool = verbosity_option,
    output_format: ActionOutputFormat = typer.Option(
        ActionOutputFormat.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,
    ),
):
    """
    Launch an Action.
    """
    ac = create_action_client(action_url, action_scope)
    if ac:
        parsed_body = process_input(body, input_format)
        result = ac.run(parsed_body, request_id, manage_by, monitor_by)
        format_and_echo(result, output_format.get_dumper(), verbose=verbose)
    return None
Ejemplo n.º 6
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()
Ejemplo n.º 7
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()
Ejemplo n.º 8
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()
Ejemplo n.º 9
0
def action_run(
    action_url: str = typer.Option(
        ...,
        help="The url at which the target Action Provider is located.",
        prompt=True,
        callback=url_validator_callback,
    ),
    action_scope: str = typer.Option(
        None,
        help="The scope this Action Provider uses to authenticate requests.",
        callback=url_validator_callback,
    ),
    body: str = typer.Option(
        ...,
        "--body",
        "-b",
        help=
        ("The body to supply to the Action Provider. Can be a filename or raw "
         "JSON string."),
        prompt=True,
        callback=input_validator,
    ),
    request_id: str = typer.Option(
        None,
        help=(
            "An identifier to associate with this Action invocation request"),
    ),
    manage_by: List[str] = typer.Option(
        None,
        help=
        "A principal which may change the execution of the Action. The principal "
        "is the user's or group's UUID prefixed with either 'urn:globus:groups:id:' "
        "or 'urn:globus:auth:identity:' [repeatable]",
        callback=principal_validator,
    ),
    monitor_by: List[str] = typer.Option(
        None,
        help="A principal which may view the state of the Action. The principal "
        "is the user's or group's UUID prefixed with either 'urn:globus:groups:id:' "
        "or 'urn:globus:auth:identity:' [repeatable]",
        callback=principal_validator,
    ),
    verbose: bool = verbosity_option,
    output_format: OutputFormat = output_format_option,
    label: str = typer.Option(
        None,
        "--label",
        "-l",
        help="Optional label to mark this execution of the action.",
    ),
    watch: bool = typer.Option(
        False,
        "--watch",
        "-w",
        help=
        "Continuously poll this Action until it reaches a completed state.",
        show_default=True,
    ),
):
    """
    Launch an Action.
    """
    parsed_body = process_input(body)
    ac = create_action_client(action_url, action_scope)
    method = functools.partial(ac.run,
                               parsed_body,
                               request_id,
                               manage_by,
                               monitor_by,
                               label=label)
    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(ac.status, action_id)
            RequestRunner(
                method,
                format=output_format,
                verbose=verbose,
                watch=watch,
                run_once=False,
            ).run_and_render()