Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions samcli/commands/_utils/experimental.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from samcli.cli.context import Context
from samcli.cli.global_config import ConfigEntry, GlobalConfig
from samcli.commands._utils.parameterized_option import parameterized_option
from samcli.lib.utils.colors import Colored
from samcli.lib.utils.colors import Colored, Colors

LOG = logging.getLogger(__name__)

Expand Down Expand Up @@ -162,7 +162,7 @@ def update_experimental_context(show_warning=True):
if not Context.get_current_context().experimental:
Context.get_current_context().experimental = True
if show_warning:
LOG.warning(Colored().yellow(EXPERIMENTAL_WARNING))
LOG.warning(Colored().color_log(EXPERIMENTAL_WARNING, color=Colors.WARNING), extra=dict(markup=True))


def _experimental_option_callback(ctx, param, enabled: Optional[bool]):
Expand Down
40 changes: 31 additions & 9 deletions samcli/commands/local/start_api/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@
from samcli.cli.cli_config_file import TomlProvider, configuration_option
from samcli.cli.main import aws_creds_options, pass_context, print_cmdline_args
from samcli.cli.main import common_options as cli_framework_options
from samcli.commands._utils.experimental import ExperimentalFlag, is_experimental_enabled
from samcli.commands._utils.option_value_processor import process_image_options
from samcli.commands._utils.options import generate_next_command_recommendation
from samcli.commands._utils.options import (
generate_next_command_recommendation,
hook_name_click_option,
skip_prepare_infra_option,
)
from samcli.commands.local.cli_common.options import (
invoke_common_options,
local_common_options,
Expand Down Expand Up @@ -54,6 +59,10 @@
context_settings={"max_content_width": 120},
)
@configuration_option(provider=TomlProvider(section="parameters"))
@hook_name_click_option(
force_prepare=False, invalid_coexist_options=["t", "template-file", "template", "parameter-overrides"]
)
@skip_prepare_infra_option
@service_common_options(3000)
@click.option(
"--static-dir",
Expand Down Expand Up @@ -98,6 +107,8 @@ def cli(
container_host,
container_host_interface,
invoke_image,
hook_name,
skip_prepare_infra,
):
"""
`sam local start-api` command entry point
Expand Down Expand Up @@ -128,6 +139,7 @@ def cli(
container_host,
container_host_interface,
invoke_image,
hook_name,
) # pragma: no cover


Expand Down Expand Up @@ -155,6 +167,7 @@ def do_cli( # pylint: disable=R0914
container_host,
container_host_interface,
invoke_image,
hook_name,
):
"""
Implementation of the ``cli`` method, just separated out for unit testing purposes
Expand All @@ -170,6 +183,14 @@ def do_cli( # pylint: disable=R0914

LOG.debug("local start-api command is called")

if (
hook_name
and ExperimentalFlag.IaCsSupport.get(hook_name) is not None
and not is_experimental_enabled(ExperimentalFlag.IaCsSupport.get(hook_name))
):
LOG.info("Terraform Support beta feature is not enabled.")
return

processed_invoke_images = process_image_options(invoke_image)

# Pass all inputs to setup necessary context to invoke function locally.
Expand Down Expand Up @@ -202,14 +223,15 @@ def do_cli( # pylint: disable=R0914
) as invoke_context:
service = LocalApiService(lambda_invoke_context=invoke_context, port=port, host=host, static_dir=static_dir)
service.start()
command_suggestions = generate_next_command_recommendation(
[
("Validate SAM template", "sam validate"),
("Test Function in the Cloud", "sam sync --stack-name {{stack-name}} --watch"),
("Deploy", "sam deploy --guided"),
]
)
click.secho(command_suggestions, fg="yellow")
if not hook_name:
command_suggestions = generate_next_command_recommendation(
[
("Validate SAM template", "sam validate"),
("Test Function in the Cloud", "sam sync --stack-name {{stack-name}} --watch"),
("Deploy", "sam deploy --guided"),
]
)
click.secho(command_suggestions, fg="yellow")

except NoApisDefined as ex:
raise UserException(
Expand Down
4 changes: 4 additions & 0 deletions samcli/commands/local/start_api/core/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
"parameter_overrides",
]

EXTENSION_OPTIONS: List[str] = ["hook_name", "skip_prepare_infra"]

CONTAINER_OPTION_NAMES: List[str] = [
"host",
"port",
Expand Down Expand Up @@ -53,6 +55,7 @@
+ ARTIFACT_LOCATION_OPTIONS
+ CONFIGURATION_OPTION_NAMES
+ ALL_COMMON_OPTIONS
+ EXTENSION_OPTIONS
)

OPTIONS_INFO: Dict[str, Dict] = {
Expand All @@ -65,6 +68,7 @@
"Artifact Location Options": {
"option_names": {opt: {"rank": idx} for idx, opt in enumerate(ARTIFACT_LOCATION_OPTIONS)}
},
"Extension Options": {"option_names": {opt: {"rank": idx} for idx, opt in enumerate(EXTENSION_OPTIONS)}},
"Configuration Options": {
"option_names": {opt: {"rank": idx} for idx, opt in enumerate(CONFIGURATION_OPTION_NAMES)},
"extras": [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
"""
Terraform prepare property builder
"""
import logging
from json import loads
from json.decoder import JSONDecodeError
from typing import Any, Dict, Optional

from samcli.hook_packages.terraform.hooks.prepare.resource_linking import _resolve_resource_attribute
Expand All @@ -24,6 +27,8 @@
from samcli.lib.utils.resources import AWS_LAMBDA_FUNCTION as CFN_AWS_LAMBDA_FUNCTION
from samcli.lib.utils.resources import AWS_LAMBDA_LAYERVERSION as CFN_AWS_LAMBDA_LAYER_VERSION

LOG = logging.getLogger(__name__)

REMOTE_DUMMY_VALUE = "<<REMOTE DUMMY VALUE - RAISE ERROR IF IT IS STILL THERE>>"
TF_AWS_LAMBDA_FUNCTION = "aws_lambda_function"
TF_AWS_LAMBDA_LAYER_VERSION = "aws_lambda_layer_version"
Expand Down Expand Up @@ -211,6 +216,35 @@ def _check_image_config_value(image_config: Any) -> bool:
return True


def _get_json_body(tf_properties: dict, resource: TFResource) -> Any:
"""
Gets the JSON formatted body value from the API Gateway if there is one

Parameters
----------
tf_properties: dict
Properties of the terraform AWS Lambda function resource
resource: TFResource
Configuration terraform resource

Returns
-------
Any
Returns a dictonary if there is a valid body to parse, otherwise return original value
"""
body = tf_properties.get("body")

if isinstance(body, str):
try:
return loads(body)
except JSONDecodeError:
pass

LOG.debug(f"Failed to load JSON body for API Gateway body, returning original value: '{body}'")

return body


AWS_LAMBDA_FUNCTION_PROPERTY_BUILDER_MAPPING: PropertyBuilderMapping = {
"FunctionName": _get_property_extractor("function_name"),
"Architectures": _get_property_extractor("architectures"),
Expand All @@ -234,7 +268,7 @@ def _check_image_config_value(image_config: Any) -> bool:

AWS_API_GATEWAY_REST_API_PROPERTY_BUILDER_MAPPING: PropertyBuilderMapping = {
"Name": _get_property_extractor("name"),
"Body": _get_property_extractor("body"),
"Body": _get_json_body,
"Parameters": _get_property_extractor("parameters"),
"BinaryMediaTypes": _get_property_extractor("binary_media_types"),
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def _unsupported_reference_field(field: str, resource: Dict, config_resource: TF
False otherwise
"""
return bool(
not resource.get(field)
not (resource.get(field) or resource.get("values", {}).get(field))
and config_resource.attributes.get(field)
and isinstance(config_resource.attributes.get(field), References)
)
Expand Down
11 changes: 7 additions & 4 deletions samcli/hook_packages/terraform/hooks/prepare/translate.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
get_sam_metadata_planned_resource_value_attribute,
)
from samcli.lib.hook.exceptions import PrepareHookException
from samcli.lib.utils.colors import Colored
from samcli.lib.utils.colors import Colored, Colors
from samcli.lib.utils.resources import AWS_LAMBDA_FUNCTION as CFN_AWS_LAMBDA_FUNCTION

SAM_METADATA_RESOURCE_TYPE = "null_resource"
Expand Down Expand Up @@ -134,9 +134,12 @@ def _check_unresolvable_values(root_module: dict, root_tf_module: TFModule) -> N

if config_values and not planned_values:
LOG.warning(
Colored().yellow(
"\nUnresolvable attributes discovered in project, run terraform apply to resolve them.\n"
)
Colored().color_log(
msg="\nUnresolvable attributes discovered in project, "
"run terraform apply to resolve them.\n",
color=Colors.WARNING,
),
extra=dict(markup=True),
)

return
Expand Down
4 changes: 2 additions & 2 deletions samcli/lib/providers/api_collector.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from typing import Dict, Iterator, List, Optional, Set, Tuple, Union

from samcli.lib.providers.provider import Api, Cors
from samcli.lib.utils.colors import Colored
from samcli.lib.utils.colors import Colored, Colors
from samcli.local.apigw.authorizers.authorizer import Authorizer
from samcli.local.apigw.route import Route

Expand Down Expand Up @@ -197,7 +197,7 @@ def get_api(self) -> Api:
be validated thoroughly before deploying to production.

Testing application behaviour against authorizers deployed on AWS can be done using the sam sync command.{os.linesep}"""
LOG.warning(Colored().yellow(message))
LOG.warning(Colored().color_log(message, color=Colors.WARNING), extra=dict(markup=True))

break

Expand Down
12 changes: 10 additions & 2 deletions tests/integration/local/start_api/start_api_integ_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ class StartApiIntegBaseClass(TestCase):

do_collect_cmd_init_output: bool = False

command_list = None
project_directory = None

@classmethod
def setUpClass(cls):
# This is the directory for tests/integration which will be used to file the testdata
Expand Down Expand Up @@ -84,7 +87,8 @@ def start_api_with_retry(cls, retries=3):
def start_api(cls):
command = get_sam_command()

command_list = [command, "local", "start-api", "-t", cls.template, "-p", cls.port]
command_list = cls.command_list or [command, "local", "start-api", "-t", cls.template]
command_list.extend(["-p", cls.port])

if cls.container_mode:
command_list += ["--warm-containers", cls.container_mode]
Expand All @@ -99,7 +103,11 @@ def start_api(cls):
for image in cls.invoke_image:
command_list += ["--invoke-image", image]

cls.start_api_process = Popen(command_list, stderr=PIPE, stdout=PIPE)
cls.start_api_process = (
Popen(command_list, stderr=PIPE, stdout=PIPE)
if not cls.project_directory
else Popen(command_list, stderr=PIPE, stdout=PIPE, cwd=cls.project_directory)
)
cls.start_api_process_output = wait_for_local_process(
cls.start_api_process, cls.port, collect_output=cls.do_collect_cmd_init_output
)
Expand Down
Loading