-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat: Add click command for cloud invoke command #5238
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6cb56ec
8d024d5
dca3f4b
2bda8b7
c8ed3a1
7451951
6a75c12
08f2961
ae83406
a24a5a0
f3589a9
41fea48
008ec2c
f4c6e5a
7725924
8289236
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| """ | ||
| Command group for "cloud" suite for commands. It provides common CLI arguments for interacting with | ||
| cloud resources such as Lambda Function. | ||
| """ | ||
|
|
||
| import click | ||
|
|
||
| from samcli.commands.cloud.invoke.cli import cli as invoke_cli | ||
|
|
||
|
|
||
| @click.group() | ||
| def cli(): | ||
| """ | ||
| Interact with your Serverless application in the cloud for quick development & testing | ||
| """ | ||
|
|
||
|
|
||
| # Add individual commands under this group | ||
| cli.add_command(invoke_cli) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| """CLI command for "invoke" command.""" | ||
| import logging | ||
| from io import TextIOWrapper | ||
| from typing import cast | ||
|
|
||
| import click | ||
|
|
||
| from samcli.cli.cli_config_file import TomlProvider, configuration_option | ||
| from samcli.cli.context import Context | ||
| from samcli.cli.main import aws_creds_options, common_options, pass_context, print_cmdline_args | ||
| from samcli.cli.types import RemoteInvokeOutputFormatType | ||
| from samcli.commands._utils.options import remote_invoke_parameter_option | ||
| from samcli.lib.cli_validation.remote_invoke_options_validations import ( | ||
| event_and_event_file_options_validation, | ||
| stack_name_or_resource_id_atleast_one_option_validation, | ||
| ) | ||
| from samcli.lib.remote_invoke.remote_invoke_executors import RemoteInvokeOutputFormat | ||
| from samcli.lib.telemetry.metric import track_command | ||
| from samcli.lib.utils.version_checker import check_newer_version | ||
|
|
||
| LOG = logging.getLogger(__name__) | ||
|
|
||
| HELP_TEXT = """ | ||
| Invoke or send an event to cloud resources in your CFN stack | ||
| """ | ||
| SHORT_HELP = "Invoke a deployed resource in the cloud" | ||
|
|
||
|
|
||
| @click.command("invoke", help=HELP_TEXT, short_help=SHORT_HELP) | ||
| @configuration_option(provider=TomlProvider(section="parameters")) | ||
| @click.option("--stack-name", required=False, help="Name of the stack to get the resource information from") | ||
| @click.option("--resource-id", required=False, help="Name of the resource that will be invoked") | ||
| @click.option( | ||
| "--event", | ||
| "-e", | ||
| help="The event that will be sent to the resource. The target parameter will depend on the resource type. " | ||
| "For instance: 'Payload' for Lambda", | ||
| ) | ||
| @click.option( | ||
| "--event-file", | ||
| type=click.File("r", encoding="utf-8"), | ||
| help="The file that contains the event that will be sent to the resource", | ||
| ) | ||
| @click.option( | ||
| "--output-format", | ||
| help="Output format for the boto API response", | ||
| default=RemoteInvokeOutputFormat.DEFAULT.name.lower(), | ||
| type=RemoteInvokeOutputFormatType(RemoteInvokeOutputFormat), | ||
| ) | ||
| @remote_invoke_parameter_option | ||
| @stack_name_or_resource_id_atleast_one_option_validation | ||
| @event_and_event_file_options_validation | ||
| @common_options | ||
| @aws_creds_options | ||
| @pass_context | ||
| @track_command | ||
| @check_newer_version | ||
| @print_cmdline_args | ||
| def cli( | ||
| ctx: Context, | ||
| stack_name: str, | ||
| resource_id: str, | ||
| event: str, | ||
| event_file: TextIOWrapper, | ||
| output_format: RemoteInvokeOutputFormat, | ||
| parameter: dict, | ||
| config_file: str, | ||
| config_env: str, | ||
| ) -> None: | ||
| """ | ||
| `sam cloud invoke` command entry point | ||
| """ | ||
|
|
||
| do_cli( | ||
| stack_name, | ||
| resource_id, | ||
| event, | ||
| event_file, | ||
| output_format, | ||
| parameter, | ||
| ctx.region, | ||
| ctx.profile, | ||
| config_file, | ||
| config_env, | ||
| ) | ||
|
|
||
|
|
||
| def do_cli( | ||
| stack_name: str, | ||
| resource_id: str, | ||
| event: str, | ||
| event_file: TextIOWrapper, | ||
| output_format: RemoteInvokeOutputFormat, | ||
| parameter: dict, | ||
| region: str, | ||
| profile: str, | ||
| config_file: str, | ||
| config_env: str, | ||
| ) -> None: | ||
| """ | ||
| Implementation of the ``cli`` method | ||
| """ | ||
| from samcli.commands.cloud.remote_invoke_context import RemoteInvokeContext | ||
| from samcli.commands.exceptions import UserException | ||
| from samcli.lib.remote_invoke.exceptions import ( | ||
| ErrorBotoApiCallException, | ||
| InvalideBotoResponseException, | ||
| InvalidResourceBotoParameterException, | ||
| ) | ||
| from samcli.lib.remote_invoke.remote_invoke_executors import RemoteInvokeExecutionInfo | ||
| from samcli.lib.utils.boto_utils import get_boto_client_provider_with_config, get_boto_resource_provider_with_config | ||
|
|
||
| boto_client_provider = get_boto_client_provider_with_config(region_name=region) | ||
| boto_resource_provider = get_boto_resource_provider_with_config(region_name=region) | ||
| try: | ||
| with RemoteInvokeContext( | ||
| boto_client_provider=boto_client_provider, | ||
| boto_resource_provider=boto_resource_provider, | ||
| stack_name=stack_name, | ||
| resource_id=resource_id, | ||
| ) as remote_invoke_context: | ||
|
|
||
| remote_invoke_input = RemoteInvokeExecutionInfo( | ||
| payload=event, payload_file=event_file, parameters=parameter, output_format=output_format | ||
| ) | ||
|
|
||
| remote_invoke_result = remote_invoke_context.run(remote_invoke_input=remote_invoke_input) | ||
|
|
||
| if remote_invoke_result.is_succeeded(): | ||
| LOG.debug("Invoking resource was successfull, writing response to stdout") | ||
| if remote_invoke_result.log_output: | ||
| LOG.debug("Writing log output to stderr") | ||
| remote_invoke_context.stderr.write(remote_invoke_result.log_output.encode()) | ||
| output_response = cast(str, remote_invoke_result.response) | ||
| remote_invoke_context.stdout.write(output_response.encode()) | ||
| else: | ||
| raise cast(Exception, remote_invoke_result.exception) | ||
| except (ErrorBotoApiCallException, InvalideBotoResponseException, InvalidResourceBotoParameterException) as ex: | ||
| raise UserException(str(ex), wrapped_from=ex.__class__.__name__) from ex |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,7 +4,7 @@ | |
| import logging | ||
| from typing import Optional, cast | ||
|
|
||
| from samcli.commands.remote_invoke.exceptions import ( | ||
| from samcli.commands.cloud.exceptions import ( | ||
| AmbiguousResourceForRemoteInvoke, | ||
| InvalidRemoteInvokeParameters, | ||
| NoExecutorFoundForRemoteInvoke, | ||
|
|
@@ -13,6 +13,7 @@ | |
| ) | ||
| from samcli.lib.remote_invoke.remote_invoke_executor_factory import RemoteInvokeExecutorFactory | ||
| from samcli.lib.remote_invoke.remote_invoke_executors import RemoteInvokeExecutionInfo | ||
| from samcli.lib.utils import osutils | ||
| from samcli.lib.utils.arn_utils import ARNParts, InvalidArnValue | ||
| from samcli.lib.utils.boto_utils import BotoProviderType | ||
| from samcli.lib.utils.cloudformation import ( | ||
|
|
@@ -22,6 +23,7 @@ | |
| get_resource_summary_from_physical_id, | ||
| ) | ||
| from samcli.lib.utils.resources import AWS_LAMBDA_FUNCTION | ||
| from samcli.lib.utils.stream_writer import StreamWriter | ||
|
|
||
| LOG = logging.getLogger(__name__) | ||
|
|
||
|
|
@@ -186,3 +188,29 @@ def _get_from_physical_resource_id(self) -> CloudFormationResourceSummary: | |
| f"Please provide full resource ARN or --stack-name to resolve the ambiguity." | ||
| ) | ||
| return resource_summary | ||
|
|
||
| @property | ||
| def stdout(self) -> StreamWriter: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be more common than here?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I added it to the context because if we decide to add another handle, for instance log_file option that |
||
| """ | ||
| Returns stream writer for stdout to output Lambda function logs to | ||
|
|
||
| Returns | ||
| ------- | ||
| samcli.lib.utils.stream_writer.StreamWriter | ||
| Stream writer for stdout | ||
| """ | ||
| stream = osutils.stdout() | ||
| return StreamWriter(stream, auto_flush=True) | ||
|
|
||
| @property | ||
| def stderr(self) -> StreamWriter: | ||
| """ | ||
| Returns stream writer for stderr to output Lambda function errors to | ||
|
|
||
| Returns | ||
| ------- | ||
| samcli.lib.utils.stream_writer.StreamWriter | ||
| Stream writer for stderr | ||
| """ | ||
| stream = osutils.stderr() | ||
| return StreamWriter(stream, auto_flush=True) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry that I didn't see this one before, but we may just hold on to
remote invokeand change it afterwards if we decide to move forward withcloud invokename.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup that's right, left it as remote invoke here to keep it consistent with other places that use remote invoke. We can refactor all modules/classes/variable names once we confirm the name to be used.