diff --git a/python/cross-stack-resources/REAMDE.md b/python/cross-stack-resources/REAMDE.md new file mode 100644 index 000000000..604e86e39 --- /dev/null +++ b/python/cross-stack-resources/REAMDE.md @@ -0,0 +1,59 @@ + +# Passing References Between Stacks! + +These two folders contain examples of how to pass resources between stacks. + +In each folder, you can run the following commands to synthesize the CDK +Applications. + +To manually create a virtualenv on MacOS and Linux: + +``` +$ python3 -m venv .env +``` + +After the init process completes and the virtualenv is created, you can use the following +step to activate your virtualenv. + +``` +$ source .env/bin/activate +``` + +If you are a Windows platform, you would activate the virtualenv like this: + +``` +% .env\Scripts\activate.bat +``` + +Once the virtualenv is activated, you can install the required dependencies. + +``` +$ pip install -r requirements.txt +``` + +At this point you can now synthesize the CloudFormation template for this code. + +``` +$ cdk synth +``` + +You can now begin exploring the source code, contained in the hello directory. +There is also a very trivial test included that can be run like this: + +``` +$ pytest +``` + +To add additional dependencies, for example other CDK libraries, just add to +your requirements.txt file and rerun the `pip install -r requirements.txt` +command. + +## Useful commands + + * `cdk ls` list all stacks in the app + * `cdk synth` emits the synthesized CloudFormation template + * `cdk deploy` deploy this stack to your default AWS account/region + * `cdk diff` compare deployed stack with current state + * `cdk docs` open CDK documentation + +Enjoy! diff --git a/python/cross-stack-resources/native-objects/README.md b/python/cross-stack-resources/native-objects/README.md new file mode 100644 index 000000000..32e18aa61 --- /dev/null +++ b/python/cross-stack-resources/native-objects/README.md @@ -0,0 +1,26 @@ + +# Native Objects Example For Passing Resources Between Stacks! + +One of my favorite parts about CDK is that I don't have to be concerned with how +the underlying cloudformation expects resources. Ideally the level of +abstraction that I want to deal with is that I have a Lambda Function in one +stack and I want to just hand the whole function to other stacks that need it. +I do not have to worry about whether API Gateway expects a Function Name or a +Function ARN or some other identifier for a Function, I can simply pass the +Function Object to the stacks that need it and let CDK handle the details. + +In this example we create an AWS Lambda Function in one stack and then make it +available as a property of that stack for other stacks to consume. + +in infrastructure_stack.py: +```python +@property +def main_function(self) -> lambda_.IFunction: + return self._function +``` + +We later refrence this property in app.py as follows: +```python +infra.main_function +``` +where `infra` is the variable we use to identify our InfrastructureStack. \ No newline at end of file diff --git a/python/cross-stack-resources/native-objects/app.py b/python/cross-stack-resources/native-objects/app.py new file mode 100644 index 000000000..1bf3a516b --- /dev/null +++ b/python/cross-stack-resources/native-objects/app.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 + +from aws_cdk import core + +from native_objects.application_stack import ApplicationStack +from native_objects.infrastructure_stack import InfrastructureStack + + +app = core.App() + +env={'region': 'us-west-2'} +# Base infrastructure stack, Lambda Functions, DynamoDB Tables, etc.... +infra = InfrastructureStack(app, "infrastructure", env=env) + +# Application stack that generally changes independently of the underlying infrastructure stack +application = ApplicationStack(app, "application", referenced_function=infra.main_function, env=env) + +app.synth() diff --git a/python/cross-stack-resources/native-objects/cdk.json b/python/cross-stack-resources/native-objects/cdk.json new file mode 100644 index 000000000..b4baa1022 --- /dev/null +++ b/python/cross-stack-resources/native-objects/cdk.json @@ -0,0 +1,3 @@ +{ + "app": "python3 app.py" +} diff --git a/python/cross-stack-resources/native-objects/native_objects/__init__.py b/python/cross-stack-resources/native-objects/native_objects/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/python/cross-stack-resources/native-objects/native_objects/application_stack.py b/python/cross-stack-resources/native-objects/native_objects/application_stack.py new file mode 100644 index 000000000..647e7b5aa --- /dev/null +++ b/python/cross-stack-resources/native-objects/native_objects/application_stack.py @@ -0,0 +1,13 @@ +from aws_cdk import ( + aws_lambda as lambda_, + aws_apigateway as apigw, + core +) + +class ApplicationStack(core.Stack): + + def __init__(self, scope: core.Construct, id: str, referenced_function: lambda_.IFunction, **kwargs) -> None: + super().__init__(scope, id, **kwargs) + + my_api = apigw.LambdaRestApi(self, "myRestAPI", handler=referenced_function) + diff --git a/python/cross-stack-resources/native-objects/native_objects/infrastructure_stack.py b/python/cross-stack-resources/native-objects/native_objects/infrastructure_stack.py new file mode 100644 index 000000000..40e3be29d --- /dev/null +++ b/python/cross-stack-resources/native-objects/native_objects/infrastructure_stack.py @@ -0,0 +1,25 @@ +from aws_cdk import ( + aws_lambda as lambda_, + core +) + +class InfrastructureStack(core.Stack): + + def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: + super().__init__(scope, id, **kwargs) + + my_main_func = lambda_.Function( + self, + "myMainFunction", + code=lambda_.InlineCode("def main(event, context)\n print('hello, world')"), + handler='index.main', + runtime=lambda_.Runtime.PYTHON_3_7 + ) + + # We assign the function to a local variable for the Object. + self._function = my_main_func + + # Using the property decorator + @property + def main_function(self) -> lambda_.IFunction: + return self._function diff --git a/python/cross-stack-resources/native-objects/requirements.txt b/python/cross-stack-resources/native-objects/requirements.txt new file mode 100644 index 000000000..ae60ed5f1 --- /dev/null +++ b/python/cross-stack-resources/native-objects/requirements.txt @@ -0,0 +1,2 @@ +-e . +pytest diff --git a/python/cross-stack-resources/native-objects/setup.py b/python/cross-stack-resources/native-objects/setup.py new file mode 100644 index 000000000..ff51f316e --- /dev/null +++ b/python/cross-stack-resources/native-objects/setup.py @@ -0,0 +1,47 @@ +import setuptools + + +with open("README.md") as fp: + long_description = fp.read() + + +setuptools.setup( + name="native-objects", + version="1.0.0", + + description="A python CDK example for passing resources between stacks", + long_description=long_description, + long_description_content_type="text/markdown", + + author="Richard Boyd", + + package_dir={"": "native_objects"}, + packages=setuptools.find_packages(where="native_objects"), + + install_requires=[ + "aws-cdk.core", + "aws-cdk.aws_apigateway", + "aws-cdk.aws_lambda" + ], + + python_requires=">=3.6", + + classifiers=[ + "Development Status :: 4 - Beta", + + "Intended Audience :: Developers", + + "License :: OSI Approved :: Apache Software License", + + "Programming Language :: JavaScript", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + + "Topic :: Software Development :: Code Generators", + "Topic :: Utilities", + + "Typing :: Typed", + ], +) diff --git a/python/cross-stack-resources/native-objects/source.bat b/python/cross-stack-resources/native-objects/source.bat new file mode 100644 index 000000000..8f5744291 --- /dev/null +++ b/python/cross-stack-resources/native-objects/source.bat @@ -0,0 +1,13 @@ +@echo off + +rem The sole purpose of this script is to make the command +rem +rem source .env/bin/activate +rem +rem (which activates a Python virtualenv on Linux or Mac OS X) work on Windows. +rem On Windows, this command just runs this batch file (the argument is ignored). +rem +rem Now we don't need to document a Windows command for activating a virtualenv. + +echo Executing .env\Scripts\activate.bat for you +.env\Scripts\activate.bat diff --git a/python/cross-stack-resources/raw-strings/README.md b/python/cross-stack-resources/raw-strings/README.md new file mode 100644 index 000000000..d02924385 --- /dev/null +++ b/python/cross-stack-resources/raw-strings/README.md @@ -0,0 +1,24 @@ + +# Raw String Example For Passing Resources Between Stacks! + +If you're coming from a strong background in cloudformation, you may either +have a preference for passing resources as strings (the way AWS Cloudformation +does natively) or your existing infrastructure may already extensively leverage +imports/exports and you'd like to maintain a consistent paradigm across your +applications. + +In this example we create an AWS Lambda Function in one stack and then make its +ARN available as a property of that stack for other stacks to consume. + +in infrastructure_stack.py: +```python +@property +def main_function_arn(self): + return self._function_arn +``` + +We later refrence this property in app.py as follows: +```python +infra.main_function_arn +``` +where `infra` is the variable we use to identify our InfrastructureStack. \ No newline at end of file diff --git a/python/cross-stack-resources/raw-strings/app.py b/python/cross-stack-resources/raw-strings/app.py new file mode 100644 index 000000000..aae72f9f1 --- /dev/null +++ b/python/cross-stack-resources/raw-strings/app.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 + +from aws_cdk import core + +from raw_strings.application_stack import ApplicationStack +from raw_strings.infrastructure_stack import InfrastructureStack + + +app = core.App() + +env={'region': 'us-west-2'} +# Base infrastructure stack, Lambda Functions, DynamoDB Tables, etc.... +infra = InfrastructureStack(app, "infrastructure", env=env) + +# Application stack that generally changes independently of the underlying infrastructure stack +application = ApplicationStack(app, "application", lambda_arn=infra.main_function_arn, env=env) + +app.synth() diff --git a/python/cross-stack-resources/raw-strings/cdk.json b/python/cross-stack-resources/raw-strings/cdk.json new file mode 100644 index 000000000..b4baa1022 --- /dev/null +++ b/python/cross-stack-resources/raw-strings/cdk.json @@ -0,0 +1,3 @@ +{ + "app": "python3 app.py" +} diff --git a/python/cross-stack-resources/raw-strings/raw_strings/__init__.py b/python/cross-stack-resources/raw-strings/raw_strings/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/python/cross-stack-resources/raw-strings/raw_strings/application_stack.py b/python/cross-stack-resources/raw-strings/raw_strings/application_stack.py new file mode 100644 index 000000000..fffcabd34 --- /dev/null +++ b/python/cross-stack-resources/raw-strings/raw_strings/application_stack.py @@ -0,0 +1,14 @@ +from aws_cdk import ( + aws_lambda as lambda_, + aws_apigateway as apigw, + core +) + +class ApplicationStack(core.Stack): + + def __init__(self, scope: core.Construct, id: str, lambda_arn: str, **kwargs) -> None: + super().__init__(scope, id, **kwargs) + + referenced_function = lambda_.Function.from_function_arn(self, id="LocalNameForFunction", function_arn=lambda_arn) + my_api = apigw.LambdaRestApi(self, "myRestAPI", handler=referenced_function) + diff --git a/python/cross-stack-resources/raw-strings/raw_strings/infrastructure_stack.py b/python/cross-stack-resources/raw-strings/raw_strings/infrastructure_stack.py new file mode 100644 index 000000000..f5d29d103 --- /dev/null +++ b/python/cross-stack-resources/raw-strings/raw_strings/infrastructure_stack.py @@ -0,0 +1,26 @@ +from aws_cdk import ( + aws_lambda as lambda_, + aws_dynamodb as ddb, + core +) + +class InfrastructureStack(core.Stack): + + def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: + super().__init__(scope, id, **kwargs) + + my_main_func = lambda_.Function( + self, + "myMainFunction", + code=lambda_.InlineCode("def main(event, context)\n print('hello, world')"), + handler='index.main', + runtime=lambda_.Runtime.PYTHON_3_7 + ) + + # We assign the function's arn to a local variable for the Object. + self._function_arn = my_main_func.function_arn + + # Using the property decorator + @property + def main_function_arn(self): + return self._function_arn diff --git a/python/cross-stack-resources/raw-strings/requirements.txt b/python/cross-stack-resources/raw-strings/requirements.txt new file mode 100644 index 000000000..ae60ed5f1 --- /dev/null +++ b/python/cross-stack-resources/raw-strings/requirements.txt @@ -0,0 +1,2 @@ +-e . +pytest diff --git a/python/cross-stack-resources/raw-strings/setup.py b/python/cross-stack-resources/raw-strings/setup.py new file mode 100644 index 000000000..11c9b7248 --- /dev/null +++ b/python/cross-stack-resources/raw-strings/setup.py @@ -0,0 +1,48 @@ +import setuptools + + +with open("README.md") as fp: + long_description = fp.read() + + +setuptools.setup( + name="raw_strings", + version="0.0.1", + + description="A sample CDK Python app", + long_description=long_description, + long_description_content_type="text/markdown", + + author="author", + + package_dir={"": "raw_strings"}, + packages=setuptools.find_packages(where="raw_strings"), + + install_requires=[ + "aws-cdk.core", + "aws-cdk.aws_apigateway", + "aws-cdk.aws_lambda", + "aws-cdk.aws_dynamodb" + ], + + python_requires=">=3.6", + + classifiers=[ + "Development Status :: 4 - Beta", + + "Intended Audience :: Developers", + + "License :: OSI Approved :: Apache Software License", + + "Programming Language :: JavaScript", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + + "Topic :: Software Development :: Code Generators", + "Topic :: Utilities", + + "Typing :: Typed", + ], +) diff --git a/python/cross-stack-resources/raw-strings/source.bat b/python/cross-stack-resources/raw-strings/source.bat new file mode 100644 index 000000000..8f5744291 --- /dev/null +++ b/python/cross-stack-resources/raw-strings/source.bat @@ -0,0 +1,13 @@ +@echo off + +rem The sole purpose of this script is to make the command +rem +rem source .env/bin/activate +rem +rem (which activates a Python virtualenv on Linux or Mac OS X) work on Windows. +rem On Windows, this command just runs this batch file (the argument is ignored). +rem +rem Now we don't need to document a Windows command for activating a virtualenv. + +echo Executing .env\Scripts\activate.bat for you +.env\Scripts\activate.bat