def action_release( 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, ), action_id: str = typer.Argument(...), verbose: bool = verbosity_option, output_format: ActionOutputFormat = typer.Option( ActionOutputFormat.json, "--format", "-f", help="Output display format.", case_sensitive=False, show_default=True, ), ): """ Remove an Action's execution history by its ACTION_ID. """ ac = create_action_client(action_url, action_scope) if ac: result = ac.release(action_id) format_and_echo(result, output_format.get_dumper(), verbose=verbose) return None
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)
def action_introspect( 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, ), verbose: bool = verbosity_option, output_format: ActionOutputFormat = typer.Option( ActionOutputFormat.json, "--format", "-f", help="Output display format.", case_sensitive=False, show_default=True, ), ): """ Introspect an Action Provider's schema. """ ac = create_action_client(action_url, action_scope) if ac is not None: result = ac.introspect() format_and_echo(result, output_format.get_dumper(), verbose=verbose) return None
def queue_display( queue_id: str = typer.Argument(...), verbose: bool = verbosity_option, ): """ Display the description of a Queue based on its id. """ qc = create_queues_client(CLIENT_ID) queue = qc.get_queue(queue_id) format_and_echo(queue, verbose=verbose)
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)
def queue_delete( queue_id: str = typer.Argument(...), verbose: bool = verbosity_option, ): """ Delete a Queue based on its id. You must have either created the Queue or have a role defined on the Queue. """ qc = create_queues_client(CLIENT_ID) queue = qc.delete_queue(queue_id) format_and_echo(queue, verbose=verbose)
def queue_delete_message( queue_id: str = typer.Argument(...), receipt_handle: List[str] = typer.Option( ..., help=("A receipt_handle value returned by a previous call to " "receive message. [repeatable]"), ), verbose: bool = verbosity_option, ): """ Notify a Queue that a message has been processed. """ qc = create_queues_client(CLIENT_ID) message_delete = qc.delete_messages(queue_id, receipt_handle) format_and_echo(message_delete, verbose=verbose)
def queue_receive( queue_id: str = typer.Argument(...), max_messages: int = typer.Option( None, help="The maximum number of messages to retrieve from the Queue", min=0), verbose: bool = verbosity_option, ): """ Receive a message from a Queue. You must have the "receiver" role on the Queue to perform this action. """ qc = create_queues_client(CLIENT_ID) queue = qc.receive_messages(queue_id, max_messages=max_messages) format_and_echo(queue, verbose=verbose)
def queue_list( roles: List[QueueRole] = typer.Option( [QueueRole.admin], "--role", "-r", help="Display Queues where you have the selected role. [repeatable]", case_sensitive=False, show_default=True, ), verbose: bool = verbosity_option, ): """ List Queues for which you have access. """ qc = create_queues_client(CLIENT_ID) queues = qc.list_queues(roles=[r.value for r in roles]) format_and_echo(queues, verbose=verbose)
def queue_update( queue_id: str = typer.Argument(...), label: str = typer.Option( ..., help="A convenient name to identify the new Queue."), admins: List[str] = typer.Option( ..., "--admin", help="The Principal URNs allowed to administer the Queue. [repeatable]", callback=principal_validator, ), senders: List[str] = typer.Option( ..., "--sender", help="The Principal URNs allowed to send to the Queue. [repeatable]", callback=principal_validator, ), receivers: List[str] = typer.Option( ..., "--receiver", help= "The Principal URNs allowed to receive from the Queue. [repeatable]", callback=principal_validator, ), delivery_timeout: int = typer.Option( ..., help= ("The minimum amount of time (in seconds) that the Queue Service should " "wait for a message-delete request after delivering a message before " "making the message visible for receiving by other consumers once " "again. If used in conjunction with 'receiver_url' this value " "represents the minimum amount of time (in seconds) that the Queue " "Service should attempt to retry delivery of messages to the " "'receiver_url' if delivery is not initially successful"), min=1, max=1209600, ), verbose: bool = verbosity_option, ): """ Update a Queue's properties. Requires the admin role on the Queue. """ qc = create_queues_client(CLIENT_ID) queues = qc.update_queue(queue_id, label, admins, senders, receivers, delivery_timeout) format_and_echo(queues, verbose=verbose)
def _format_and_display_flow(flow_resp: GlobusHTTPResponse, output_format: FlowDisplayFormat, verbose=False): """ Diplays a flow as either JSON, graphviz, or an image """ if verbose: display_http_details(flow_resp) if output_format is FlowDisplayFormat.json: format_and_echo(flow_resp, json.dumps) elif output_format is FlowDisplayFormat.yaml: format_and_echo(flow_resp, yaml.dump) elif output_format in (FlowDisplayFormat.graphviz, FlowDisplayFormat.image): graphviz_out = graphviz_format(flow_resp.data["definition"]) if output_format == FlowDisplayFormat.graphviz: typer.echo(graphviz_out.source) else: graphviz_out.render("flows-output/graph", view=True, cleanup=True)
def queue_send( queue_id: str = typer.Argument(...), message: str = typer.Option( ..., "--message", "-m", help= "Text of the message to send. Files may be referenced by prefixing the '@' character to the value.", prompt=True, callback=text_validator_callback, ), verbose: bool = verbosity_option, ): """ Send a message to a Queue. You must have the "sender" role on the Queue to perform this action. """ qc = create_queues_client(CLIENT_ID) message_send = qc.send_message(queue_id, message) format_and_echo(message_send, 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_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)
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