Example #1
0
    def test_can_build_lambda_function_app_with_vpc_config(
            self, sample_app_lambda_only):
        @sample_app_lambda_only.lambda_function()
        def foo(event, context):
            pass

        builder = ApplicationGraphBuilder()
        config = self.create_config(sample_app_lambda_only,
                                    iam_role_arn='role:arn',
                                    security_group_ids=['sg1', 'sg2'],
                                    subnet_ids=['sn1', 'sn2'])
        application = builder.build(config, stage_name='dev')

        assert application.resources[0] == models.LambdaFunction(
            resource_name='myfunction',
            function_name='lambda-only-dev-myfunction',
            environment_variables={},
            runtime=config.lambda_python_version,
            handler='app.myfunction',
            tags=config.tags,
            timeout=None,
            memory_size=None,
            deployment_package=models.DeploymentPackage(
                models.Placeholder.BUILD_STAGE),
            role=models.PreCreatedIAMRole('role:arn'),
            security_group_ids=['sg1', 'sg2'],
            subnet_ids=['sn1', 'sn2'],
            layers=[],
            reserved_concurrency=None,
            xray=None,
        )
Example #2
0
 def test_can_build_lambda_function_app_with_reserved_concurrency(
         self, sample_app_lambda_only):
     # This is the simplest configuration we can get.
     builder = ApplicationGraphBuilder()
     config = self.create_config(sample_app_lambda_only,
                                 iam_role_arn='role:arn',
                                 reserved_concurrency=5)
     application = builder.build(config, stage_name='dev')
     # The top level resource is always an Application.
     assert isinstance(application, models.Application)
     assert len(application.resources) == 1
     assert application.resources[0] == models.LambdaFunction(
         resource_name='myfunction',
         function_name='lambda-only-dev-myfunction',
         environment_variables={},
         runtime=config.lambda_python_version,
         handler='app.myfunction',
         tags=config.tags,
         timeout=None,
         memory_size=None,
         deployment_package=models.DeploymentPackage(
             models.Placeholder.BUILD_STAGE),
         role=models.PreCreatedIAMRole('role:arn'),
         security_group_ids=[],
         subnet_ids=[],
         layers=[],
         reserved_concurrency=5,
         xray=None,
     )
Example #3
0
 def test_can_build_app_with_domain_name(self, sample_app):
     domain_name = {
         'domain_name': 'example.com',
         'tls_version': 'TLS_1_0',
         'certificate_arn': 'certificate_arn',
         'tags': {
             'some_key1': 'some_value1',
             'some_key2': 'some_value2'
         },
         'url_prefix': '/'
     }
     config = self.create_config(
         sample_app,
         app_name='rest-api-app',
         api_gateway_endpoint_type='REGIONAL',
         api_gateway_custom_domain=domain_name,
     )
     builder = ApplicationGraphBuilder()
     application = builder.build(config, stage_name='dev')
     rest_api = application.resources[0]
     assert isinstance(rest_api, models.RestAPI)
     domain_name = rest_api.domain_name
     api_mapping = domain_name.api_mapping
     assert isinstance(domain_name, models.DomainName)
     assert isinstance(api_mapping, models.APIMapping)
     assert api_mapping.mount_path == '(none)'
Example #4
0
 def test_can_build_private_rest_api(self, sample_app):
     config = self.create_config(sample_app,
                                 app_name='sample-app',
                                 api_gateway_endpoint_type='PRIVATE',
                                 api_gateway_endpoint_vpce='vpce-abc123')
     builder = ApplicationGraphBuilder()
     application = builder.build(config, stage_name='dev')
     rest_api = application.resources[0]
     assert isinstance(rest_api, models.RestAPI)
     assert rest_api.policy.document == {
         'Version':
         '2012-10-17',
         'Statement': [
             {
                 'Action': 'execute-api:Invoke',
                 'Effect': 'Allow',
                 'Principal': '*',
                 'Resource': 'arn:*:execute-api:*:*:*',
                 'Condition': {
                     'StringEquals': {
                         'aws:SourceVpce': 'vpce-abc123'
                     }
                 }
             },
         ]
     }
Example #5
0
    def test_can_create_websocket_app_missing_connect(
            self, websocket_app_without_connect):
        config = self.create_config(websocket_app_without_connect,
                                    app_name='websocket-app',
                                    autogen_policy=True)
        builder = ApplicationGraphBuilder()
        application = builder.build(config, stage_name='dev')
        assert len(application.resources) == 1
        websocket_api = application.resources[0]
        assert isinstance(websocket_api, models.WebsocketAPI)
        assert websocket_api.resource_name == 'websocket_api'
        assert sorted(websocket_api.routes) == sorted(
            ['$default', '$disconnect'])
        assert websocket_api.api_gateway_stage == 'api'

        connect_function = websocket_api.connect_function
        assert connect_function is None

        message_function = websocket_api.message_function
        assert message_function.resource_name == 'websocket_message'
        assert message_function.handler == 'app.message'

        disconnect_function = websocket_api.disconnect_function
        assert disconnect_function.resource_name == 'websocket_disconnect'
        assert disconnect_function.handler == 'app.disconnect'
Example #6
0
 def test_can_build_rest_api_with_authorizer(self, sample_app_with_auth):
     config = self.create_config(sample_app_with_auth,
                                 app_name='rest-api-app',
                                 autogen_policy=True)
     builder = ApplicationGraphBuilder()
     application = builder.build(config, stage_name='dev')
     rest_api = application.resources[0]
     assert len(rest_api.authorizers) == 1
     assert isinstance(rest_api.authorizers[0], models.LambdaFunction)
Example #7
0
 def test_scheduled_event_models(self, sample_app_schedule_only):
     config = self.create_config(sample_app_schedule_only,
                                 app_name='scheduled-event',
                                 autogen_policy=True)
     builder = ApplicationGraphBuilder()
     application = builder.build(config, stage_name='dev')
     assert len(application.resources) == 1
     event = application.resources[0]
     assert isinstance(event, models.ScheduledEvent)
     assert event.resource_name == 'cron-event'
     assert event.rule_name == 'scheduled-event-dev-cron-event'
     assert isinstance(event.lambda_function, models.LambdaFunction)
     assert event.lambda_function.resource_name == 'cron'
Example #8
0
    def test_exception_raised_when_missing_vpc_params(self,
                                                      sample_app_lambda_only):
        @sample_app_lambda_only.lambda_function()
        def foo(event, context):
            pass

        builder = ApplicationGraphBuilder()
        config = self.create_config(sample_app_lambda_only,
                                    iam_role_arn='role:arn',
                                    security_group_ids=['sg1', 'sg2'],
                                    subnet_ids=[])
        with pytest.raises(ChaliceBuildError):
            builder.build(config, stage_name='dev')
Example #9
0
 def test_cloudwatch_event_models(self, sample_cloudwatch_event_app):
     config = self.create_config(sample_cloudwatch_event_app,
                                 app_name='cloudwatch-event',
                                 autogen_policy=True)
     builder = ApplicationGraphBuilder()
     application = builder.build(config, stage_name='dev')
     assert len(application.resources) == 1
     event = application.resources[0]
     assert isinstance(event, models.CloudWatchEvent)
     assert event.resource_name == 'foo-event'
     assert event.rule_name == 'cloudwatch-event-dev-foo-event'
     assert isinstance(event.lambda_function, models.LambdaFunction)
     assert event.lambda_function.resource_name == 'foo'
Example #10
0
def appgraph(ctx, autogen_policy, profile, api_gateway_stage, stage):
    # type: (click.Context, Optional[bool], str, str, str) -> None
    """Generate and display the application graph."""
    factory = ctx.obj['factory']  # type: CLIFactory
    factory.profile = profile
    config = factory.create_config_obj(
        chalice_stage_name=stage, autogen_policy=autogen_policy,
        api_gateway_stage=api_gateway_stage,
    )
    graph_build = ApplicationGraphBuilder()
    graph = graph_build.build(config, stage)
    ui = UI()
    GraphPrettyPrint(ui).display_graph(graph)
Example #11
0
 def test_can_create_sns_event_handler(self, sample_sns_event_app):
     config = self.create_config(sample_sns_event_app,
                                 app_name='s3-event-app',
                                 autogen_policy=True)
     builder = ApplicationGraphBuilder()
     application = builder.build(config, stage_name='dev')
     assert len(application.resources) == 1
     sns_event = application.resources[0]
     assert isinstance(sns_event, models.SNSLambdaSubscription)
     assert sns_event.resource_name == 'handler-sns-subscription'
     assert sns_event.topic == 'mytopic'
     lambda_function = sns_event.lambda_function
     assert lambda_function.resource_name == 'handler'
     assert lambda_function.handler == 'app.handler'
Example #12
0
 def test_can_create_sqs_event_handler(self, sample_sqs_event_app):
     config = self.create_config(sample_sqs_event_app,
                                 app_name='sqs-event-app',
                                 autogen_policy=True)
     builder = ApplicationGraphBuilder()
     application = builder.build(config, stage_name='dev')
     assert len(application.resources) == 1
     sqs_event = application.resources[0]
     assert isinstance(sqs_event, models.SQSEventSource)
     assert sqs_event.resource_name == 'handler-sqs-event-source'
     assert sqs_event.queue == 'myqueue'
     lambda_function = sqs_event.lambda_function
     assert lambda_function.resource_name == 'handler'
     assert lambda_function.handler == 'app.handler'
Example #13
0
 def test_can_create_kinesis_event_handler(self, sample_kinesis_event_app):
     config = self.create_config(sample_kinesis_event_app,
                                 app_name='kinesis-event-app',
                                 autogen_policy=True)
     builder = ApplicationGraphBuilder()
     application = builder.build(config, stage_name='dev')
     assert len(application.resources) == 1
     kinesis_event = application.resources[0]
     assert isinstance(kinesis_event, models.KinesisEventSource)
     assert kinesis_event.resource_name == 'handler-kinesis-event-source'
     assert kinesis_event.stream == 'mystream'
     lambda_function = kinesis_event.lambda_function
     assert lambda_function.resource_name == 'handler'
     assert lambda_function.handler == 'app.handler'
Example #14
0
 def test_can_create_ddb_event_handler(self, sample_ddb_event_app):
     config = self.create_config(sample_ddb_event_app,
                                 app_name='ddb-event-app',
                                 autogen_policy=True)
     builder = ApplicationGraphBuilder()
     application = builder.build(config, stage_name='dev')
     assert len(application.resources) == 1
     ddb_event = application.resources[0]
     assert isinstance(ddb_event, models.DynamoDBEventSource)
     assert ddb_event.resource_name == 'handler-dynamodb-event-source'
     assert ddb_event.stream_arn == 'arn:aws:...:stream'
     lambda_function = ddb_event.lambda_function
     assert lambda_function.resource_name == 'handler'
     assert lambda_function.handler == 'app.handler'
Example #15
0
    def test_can_create_sqs_handler_with_queue_arn(self, sample_sqs_event_app):
        @sample_sqs_event_app.on_sqs_message(queue_arn='arn:my:queue')
        def new_handler(event):
            pass

        config = self.create_config(sample_sqs_event_app,
                                    app_name='sqs-event-app',
                                    autogen_policy=True)
        builder = ApplicationGraphBuilder()
        application = builder.build(config, stage_name='dev')
        sqs_event = application.resources[1]
        assert sqs_event.queue == models.QueueARN(arn='arn:my:queue')
        lambda_function = sqs_event.lambda_function
        assert lambda_function.resource_name == 'new_handler'
        assert lambda_function.handler == 'app.new_handler'
Example #16
0
    def test_all_lambda_functions_share_managed_layer(self,
                                                      sample_app_lambda_only):
        @sample_app_lambda_only.lambda_function()
        def second(event, context):
            pass

        builder = ApplicationGraphBuilder()
        config = self.create_config(sample_app_lambda_only,
                                    iam_role_arn='role:arn',
                                    automatic_layer=True)
        application = builder.build(config, stage_name='dev')
        assert len(application.resources) == 2
        first_layer = application.resources[0].managed_layer
        second_layer = application.resources[1].managed_layer
        assert first_layer == second_layer
def _create_deployer(
        session,  # type: Session
        config,  # type: Config
        ui,  # type: UI
        executor_cls,  # type: Type[BaseExecutor]
        recorder_cls,  # type: Type[ResultsRecorder]
):
    # type: (...) -> Deployer
    client = TypedAWSClient(session)
    osutils = OSUtils()
    return Deployer(
        application_builder=ApplicationGraphBuilder(),
        deps_builder=DependencyBuilder(),
        build_stage=create_build_stage(
            osutils,
            UI(),
            TemplatedSwaggerGenerator(),
        ),
        plan_stage=PlanStage(
            osutils=osutils,
            remote_state=RemoteState(
                client, config.deployed_resources(config.chalice_stage)),
        ),
        sweeper=ResourceSweeper(),
        executor=executor_cls(client, ui),
        recorder=recorder_cls(osutils=osutils),
    )
Example #18
0
 def test_can_build_rest_api(self, sample_app):
     config = self.create_config(sample_app,
                                 app_name='sample-app',
                                 autogen_policy=True)
     builder = ApplicationGraphBuilder()
     application = builder.build(config, stage_name='dev')
     assert len(application.resources) == 1
     rest_api = application.resources[0]
     assert isinstance(rest_api, models.RestAPI)
     assert rest_api.resource_name == 'rest_api'
     assert rest_api.api_gateway_stage == 'api'
     assert rest_api.lambda_function.resource_name == 'api_handler'
     assert rest_api.lambda_function.function_name == 'sample-app-dev'
     # The swagger document is validated elsewhere so we just
     # make sure it looks right.
     assert rest_api.swagger_doc == models.Placeholder.BUILD_STAGE
def create_app_packager(config,
                        package_format='cloudformation',
                        merge_template=None):
    # type: (Config, str, Optional[str]) -> AppPackager
    osutils = OSUtils()
    ui = UI()
    application_builder = ApplicationGraphBuilder()
    deps_builder = DependencyBuilder()
    post_processors = []  # type: List[TemplatePostProcessor]
    generator = None  # type: Union[None, TemplateGenerator]

    if package_format == 'cloudformation':
        build_stage = create_build_stage(osutils, ui, CFNSwaggerGenerator())
        post_processors.extend([
            SAMCodeLocationPostProcessor(osutils=osutils),
            TemplateMergePostProcessor(osutils=osutils,
                                       merger=TemplateDeepMerger(),
                                       merge_template=merge_template)
        ])
        generator = SAMTemplateGenerator(config)
    else:
        build_stage = create_build_stage(osutils, ui,
                                         TerraformSwaggerGenerator())
        generator = TerraformGenerator(config)
        post_processors.append(
            TerraformCodeLocationPostProcessor(osutils=osutils))

    resource_builder = ResourceBuilder(application_builder, deps_builder,
                                       build_stage)

    return AppPackager(generator, resource_builder,
                       CompositePostProcessor(post_processors), osutils)
Example #20
0
 def test_can_create_s3_event_handler(self, sample_s3_event_app):
     # TODO: don't require app name, get it from app obj.
     config = self.create_config(sample_s3_event_app,
                                 app_name='s3-event-app',
                                 autogen_policy=True)
     builder = ApplicationGraphBuilder()
     application = builder.build(config, stage_name='dev')
     assert len(application.resources) == 1
     s3_event = application.resources[0]
     assert isinstance(s3_event, models.S3BucketNotification)
     assert s3_event.resource_name == 'handler-s3event'
     assert s3_event.bucket == 'mybucket'
     assert s3_event.events == ['s3:ObjectCreated:*']
     lambda_function = s3_event.lambda_function
     assert lambda_function.resource_name == 'handler'
     assert lambda_function.handler == 'app.handler'
Example #21
0
    def test_vpc_trait_added_when_vpc_configured(self, sample_app_lambda_only):
        @sample_app_lambda_only.lambda_function()
        def foo(event, context):
            pass

        builder = ApplicationGraphBuilder()
        config = self.create_config(sample_app_lambda_only,
                                    autogen_policy=True,
                                    security_group_ids=['sg1', 'sg2'],
                                    subnet_ids=['sn1', 'sn2'])
        application = builder.build(config, stage_name='dev')

        policy = application.resources[0].role.policy
        assert policy == models.AutoGenIAMPolicy(
            document=models.Placeholder.BUILD_STAGE,
            traits=set([models.RoleTraits.VPC_NEEDED]),
        )
Example #22
0
 def test_autogen_policy_for_function(self, sample_app_lambda_only):
     # This test is just a sanity test that verifies all the params
     # for an ManagedIAMRole.  The various combinations for role
     # configuration is all tested via RoleTestCase.
     config = self.create_config(sample_app_lambda_only,
                                 autogen_policy=True)
     builder = ApplicationGraphBuilder()
     application = builder.build(config, stage_name='dev')
     function = application.resources[0]
     role = function.role
     # We should have linked a ManagedIAMRole
     assert isinstance(role, models.ManagedIAMRole)
     assert role == models.ManagedIAMRole(
         resource_name='default-role',
         role_name='lambda-only-dev',
         trust_policy=LAMBDA_TRUST_POLICY,
         policy=models.AutoGenIAMPolicy(models.Placeholder.BUILD_STAGE),
     )
Example #23
0
    def test_multiple_lambda_functions_share_role_and_package(
            self, sample_app_lambda_only):
        # We're going to add another lambda_function to our app.
        @sample_app_lambda_only.lambda_function()
        def bar(event, context):
            return {}

        builder = ApplicationGraphBuilder()
        config = self.create_config(sample_app_lambda_only,
                                    iam_role_arn='role:arn')
        application = builder.build(config, stage_name='dev')
        assert len(application.resources) == 2
        # The lambda functions by default share the same role
        assert application.resources[0].role == application.resources[1].role
        # Not just in equality but the exact same role objects.
        assert application.resources[0].role is application.resources[1].role
        # And all lambda functions share the same deployment package.
        assert (application.resources[0].deployment_package ==
                application.resources[1].deployment_package)
Example #24
0
def create_deletion_deployer(client, ui):
    # type: (TypedAWSClient, UI) -> Deployer
    return Deployer(
        application_builder=ApplicationGraphBuilder(),
        deps_builder=DependencyBuilder(),
        build_stage=BuildStage(steps=[]),
        plan_stage=NoopPlanner(),
        sweeper=ResourceSweeper(),
        executor=Executor(client, ui),
        recorder=ResultsRecorder(osutils=OSUtils()),
    )
Example #25
0
    def test_no_inject_is_already_injected(self, sample_sqs_event_app):
        @sample_sqs_event_app.on_sqs_message(queue='second-queue')
        def second_handler(event):
            pass

        config = Config.create(chalice_app=sample_sqs_event_app,
                               autogen_policy=True,
                               project_dir='.')
        builder = ApplicationGraphBuilder()
        application = builder.build(config, stage_name='dev')
        event_sources = application.resources
        role = event_sources[1].lambda_function.role
        role.policy.document = {'Statement': []}
        injector = LambdaEventSourcePolicyInjector()
        injector.handle(config, event_sources[0])
        injector.handle(config, event_sources[1])
        # Even though we have two queue handlers, we only need to
        # inject the policy once.
        assert role.policy.document == {
            'Statement': [SQS_EVENT_SOURCE_POLICY.copy()],
        }
Example #26
0
 def test_can_build_private_rest_api_custom_policy(self, tmpdir,
                                                   sample_app):
     config = self.create_config(sample_app,
                                 app_name='rest-api-app',
                                 api_gateway_policy_file='foo.json',
                                 api_gateway_endpoint_type='PRIVATE',
                                 project_dir=str(tmpdir))
     tmpdir.mkdir('.chalice').join('foo.json').write(
         serialize_to_json({
             'Version': '2012-10-17',
             'Statement': []
         }))
     application_builder = ApplicationGraphBuilder()
     build_stage = BuildStage(
         steps=[PolicyGenerator(osutils=OSUtils(), policy_gen=None)])
     application = application_builder.build(config, stage_name='dev')
     build_stage.execute(config, application.resources)
     rest_api = application.resources[0]
     assert rest_api.policy.document == {
         'Version': '2012-10-17',
         'Statement': []
     }
Example #27
0
    def test_can_create_websocket_api_with_domain_name(self,
                                                       sample_websocket_app):
        domain_name = {
            'domain_name': 'example.com',
            'tls_version': 'TLS_1_2',
            'certificate_arn': 'certificate_arn',
            'tags': {
                'tag_key1': 'tag_value1',
                'tag_key2': 'tag_value2'
            }
        }
        config = self.create_config(sample_websocket_app,
                                    app_name='websocket-app',
                                    autogen_policy=True,
                                    websocket_api_custom_domain=domain_name)
        builder = ApplicationGraphBuilder()
        application = builder.build(config, stage_name='dev')
        websocket_api = application.resources[0]
        assert isinstance(websocket_api, models.WebsocketAPI)

        domain_name = websocket_api.domain_name
        assert isinstance(domain_name, models.DomainName)
        assert isinstance(domain_name.api_mapping, models.APIMapping)
        assert domain_name.api_mapping.mount_path == '(none)'
Example #28
0
def create_app_packager(
        config, package_format='cloudformation',
        template_format='json', merge_template=None):
    # type: (Config, str, str, Optional[str]) -> AppPackager
    osutils = OSUtils()
    ui = UI()
    application_builder = ApplicationGraphBuilder()
    deps_builder = DependencyBuilder()
    post_processors = []  # type: List[TemplatePostProcessor]
    generator = None  # type: Union[None, TemplateGenerator]

    template_serializer = cast(TemplateSerializer, JSONTemplateSerializer())
    if package_format == 'cloudformation':
        build_stage = create_build_stage(
            osutils, ui, CFNSwaggerGenerator())
        use_yaml_serializer = template_format == 'yaml'
        if merge_template is not None and \
                YAMLTemplateSerializer.is_yaml_template(merge_template):
            # Automatically switch the serializer to yaml if they specify
            # a yaml template to merge, regardless of what template format
            # they specify.
            use_yaml_serializer = True
        if use_yaml_serializer:
            template_serializer = YAMLTemplateSerializer()
        post_processors.extend([
            SAMCodeLocationPostProcessor(osutils=osutils),
            TemplateMergePostProcessor(
                osutils=osutils,
                merger=TemplateDeepMerger(),
                template_serializer=template_serializer,
                merge_template=merge_template)])
        generator = SAMTemplateGenerator(config)
    else:
        build_stage = create_build_stage(
            osutils, ui, TerraformSwaggerGenerator())
        generator = TerraformGenerator(config)
        post_processors.append(
            TerraformCodeLocationPostProcessor(osutils=osutils))

    resource_builder = ResourceBuilder(
        application_builder, deps_builder, build_stage)

    return AppPackager(
        generator,
        resource_builder,
        CompositePostProcessor(post_processors),
        template_serializer,
        osutils)
Example #29
0
def test_role_creation(case):
    _, config = case.build()
    builder = ApplicationGraphBuilder()
    application = builder.build(config, stage_name='dev')
    case.assert_required_roles_created(application)
Example #30
0
 def create_model_from_app(self, app, config):
     builder = ApplicationGraphBuilder()
     application = builder.build(config, stage_name='dev')
     return application.resources[0]