Skip to content

Commit

Permalink
feat: enable terraform support for local start-api command (#5389)
Browse files Browse the repository at this point in the history
* feat: Enable hook-name and skip-prepare-infra flagf for sam local start-api (#5217)

* Enable hook-name flag for sam local start-api

* Format files

* test: Terraform local start-api integration tests base (#5240)

* feat: update SAM CLI with latest App Templates commit hash (#5211)

* feat: updating app templates repo hash with (a34f563f067e13df3eb350d36461b99397b6cda6)

* dummy change to trigger checks

* revert dummy commit

---------

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Mohamed Elasmar <71043312+moelasmar@users.noreply.github.com>

* Enable hook-name flag for sam local start-api

* Format files

* fix: fix failing Terraform integration test cases (#5218)

* fix: fix the failing terraform integration test cases

* fix: fix the resource address while accessing the module config resources

* fix: fix checking the experimental log integration test cases

* chore: bump version to 1.85.0 (#5226)

* chore: use the SAR Application created in testing accounts (#5221)

* chore: update aws_lambda_builders to 1.32.0 (#5215)

Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Mohamed Elasmar <71043312+moelasmar@users.noreply.github.com>

* feat: Added linking Gateway Method to Lambda Authorizer (#5228)

* Added linking method to authorizer

* Fixed docstring spelling mistake

---------

Co-authored-by: Mohamed Elasmar <71043312+moelasmar@users.noreply.github.com>

* feat: Return early during linking if no destination resources are found (#5220)

* Returns during linking if no destination resources are found

* Updated comment to correctly reflect state

* Cleaned extra word

---------

Co-authored-by: Mohamed Elasmar <71043312+moelasmar@users.noreply.github.com>

* chore: Strengthen wording on "no Auth" during deploy (#5231)

Co-authored-by: Jacob Fuss <jfuss@users.noreply.github.com>
Co-authored-by: Sriram Madapusi Vasudevan <3770774+sriram-mv@users.noreply.github.com>

* feat: Link Lambda Authorizer to Rest API (#5219)

* Link RestApiId property for Lambda Authorizers

* Updated docstring

* Format files

---------

Co-authored-by: Mohamed Elasmar <71043312+moelasmar@users.noreply.github.com>

* Terraform start-api integration tests

* Add test files

* Uncomment skip

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Mohamed Elasmar <71043312+moelasmar@users.noreply.github.com>
Co-authored-by: Lucas <12496191+lucashuy@users.noreply.github.com>
Co-authored-by: Jacob Fuss <32497805+jfuss@users.noreply.github.com>
Co-authored-by: Jacob Fuss <jfuss@users.noreply.github.com>
Co-authored-by: Sriram Madapusi Vasudevan <3770774+sriram-mv@users.noreply.github.com>

* feat: Added OpenApi body integration testing and updated property builder (#5291)

* Added OpenApi body integration testing and updated property builder

* Added more test cases

* Changed tearDown to tearDownClass

* Updated JSON body parser to handle parsing errors and added unit tests

* Removed V1 references

* feat: Terraform Authorizer resource testing (#5270)

* Added authorizer project

* Added project files

* Removed extra print

* Add request based authorizer testing

* test: Test the unsupported limitations for local start api (#5309)

* test: Test the unsupported limitations for local start api

* fix lint issues

* apply pr comments

* fix: Bug Bash UX Issues (#5387)

* Fix bug bash UX issues

* Fix beta warning printing extra characters

* Fix authorizer logging

---------

Co-authored-by: Daniel Mil <84205762+mildaniel@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Lucas <12496191+lucashuy@users.noreply.github.com>
Co-authored-by: Jacob Fuss <32497805+jfuss@users.noreply.github.com>
Co-authored-by: Jacob Fuss <jfuss@users.noreply.github.com>
Co-authored-by: Sriram Madapusi Vasudevan <3770774+sriram-mv@users.noreply.github.com>
  • Loading branch information
8 people committed Jul 3, 2023
1 parent 9877db2 commit c53db02
Show file tree
Hide file tree
Showing 25 changed files with 1,032 additions and 24 deletions.
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
36 changes: 35 additions & 1 deletion samcli/hook_packages/terraform/hooks/prepare/property_builder.py
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

0 comments on commit c53db02

Please sign in to comment.