Skip to content

Commit 97ecee0

Browse files
committed
Merge branch 'develop'
2 parents 6f3720c + d40272d commit 97ecee0

32 files changed

+542
-791
lines changed

.gitignore

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,17 @@ dmypy.json
127127

128128
# Pyre type checker
129129
.pyre/
130-
.idea/
131130
node_modules/
132131
cdk.out/
133132
websites/
134-
tmp/
133+
tmp/
134+
135+
# MacOS Files
136+
.DS_Store
137+
138+
# JetBrains Products
139+
.idea/
140+
141+
# WebflowAws config files
142+
webflow-aws-config.yaml
143+
*.zip

MANIFEST.in

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
include webflow_aws/lambda_function/cloudfront_www_edit_path_for_origin/cloudfront_www_edit_path_for_origin.zip
2-
include webflow_aws/lambda_function/s3_trigger_artifacts_upload/s3_trigger_upload_artifacts.zip
3-
include webflow_aws/templates/template_setup.yaml
41
include cdk.json
52
include requirements.txt
3+
include webflow_aws/backend/networking/functions/editPathForOrigin.js
4+
include webflow_aws/backend/compute/functions/index.checkLanguage.js
5+
include webflow_aws/backend/compute/functions/index.s3TriggerArtifactsUpload.js
6+
include webflow_aws/backend/compute/functions/package.json
7+
include webflow_aws/backend/compute/functions/yarn.lock
8+
include webflow_aws/backend/compute/functions/package-lock.json
69
recursive-exclude tests *

README.md

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
# webflow-aws
2+
3+
| 🛑 | If you already deployed one website using the **v1** version of the tool, follow the [Migration from v1 to v2](#migration-from-v1-to-v2) section before updating the tool version. |
4+
|-----|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
5+
26
An out-of-the box tool written in Python to deploy your [Webflow](https://webflow.com/) static website on AWS with a serverless architecture.
37

48
This tool uses the power of Cloud Formation to let you have your website up in minutes, with CDN and SSL Certificate enabled.
59

610
You can manage up to an infinite number of websites in the same AWS account, paying only for the real traffic. That's the beautiful part of serverless 😉
711

8-
| :point_up: | In this version, everything needs to be hosted in AWS, also your domain. |
9-
|---------------|:-------------------------------------------------------------------------|
12+
| ☝️ | In this version, everything needs to be hosted in AWS, also your domain. |
13+
|-----|:-------------------------------------------------------------------------|
1014

1115
## Getting Started
1216

@@ -19,7 +23,7 @@ In order to use this tool, you need to have:
1923
- Python 3.6 or later with pip3 installed ([instructions](https://docs.python-guide.org/starting/install3/linux/))
2024
- AWS CLI installed and configured ([instructions](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html)).
2125

22-
Finally, install the [AWS CDK command line tool](https://aws.amazon.com/cdk/?nc1=h_ls) with the following command
26+
Finally, install the [AWS CDK command line tool](https://aws.amazon.com/cdk) with the following command
2327

2428
```bash
2529
npm install -g aws-cdk
@@ -31,7 +35,7 @@ You can download and install the latest version of this tool from the Python pac
3135
as follows:
3236

3337
```bash
34-
pip3 install --upgrade webflow-aws
38+
pip3 install webflow-aws
3539
```
3640

3741
#### Advanced Installation
@@ -44,11 +48,11 @@ To use our tool, you have to clone this repository and install:
4448

4549
- Clone using HTTPs:
4650
```bash
47-
git clone https://github.com/CreateInCloud/webflow-aws.git
51+
git clone https://github.com/odfdata/webflow-aws.git
4852
```
4953
- Clone using SSH:
5054
```bash
51-
git clone [email protected]:CreateInCloud/webflow-aws.git
55+
git clone [email protected]:odfdata/webflow-aws.git
5256
```
5357

5458
After you cloned the repository, go inside the **webflow-aws** folder and generate the **.whl** package to be installed.
@@ -86,12 +90,52 @@ the available commands, and check if it's correctly installed, run the following
8690
webflow-aws --help
8791
```
8892

93+
### Migration from v1 to v2
94+
95+
If you used the **v1** version of the tool and you plan to migrate to the **v2**, remember this:
96+
97+
| ⚠️ | Running the commands below will put your current website offline for couple of minutes. Plan to run the migration when you don't have traffic on your website. |
98+
|-----|:---------------------------------------------------------------------------------------------------------------------------------------------------------------|
99+
100+
To migrate from **v1** to **v2**, you have to delete the current deployed website from the AWS Console.
101+
Unfortunately is not possible to do it using our tool since there are resources that are running at edge and it takes
102+
time to complete the deletion on AWS side.
103+
104+
These are the steps to delete your current website:
105+
106+
+ Open the configuration file you have locally (named *webflow-aws-config.yaml*), and search for the keywords
107+
+ *stack_name* and *bucket_name* and copy the values.
108+
+ Go to AWS Console and login in the account you have deployed your website.
109+
+ Search for the AWS service named **S3** and open it.
110+
+ Search for the Bucket with the same name copied before and click on the circle on the left of the name.
111+
+ Click on the **Empty** button, and now you are ready to click on **Delete** button
112+
+ Search for the AWS service named **CloudFormation** and open it.
113+
+ Search for the stack deployed, click on it and click on **Delete**
114+
+ After a couple of minutes, you will see the status stack equal to *DELETE_FAILED*
115+
+ You can now click on **Delete** again, and check the square on the left of the resource name
116+
+ Now you can click on **Delete stack**, and you are ready to upgrade your local tool.
117+
118+
119+
#### Update from v1 to v2
120+
121+
Run the following command to update the tool:
122+
123+
```bash
124+
pip3 install --upgrade webflow-aws
125+
```
126+
127+
Now you are ready to deploy your website using the new version running:
128+
129+
```bash
130+
webflow-aws publish
131+
```
132+
89133
## Deploy your website
90134

91135
You are now ready to deploy your website. Start by going to **Webflow** and download your created website as a `.zip` file
92136
([click here](https://university.webflow.com/lesson/code-export) to see a detailed guide on how to do it).
93137

94-
Once you downloaded it, create a folder and put the `.zip` file inside. The folder's name doesn't matter, but make it meaningful for you. In our guide we will use the `example-website` folder
138+
Once you downloaded it, create a folder and put the `.zip` file inside. The folder's name does not matter, but make it meaningful for you. In our guide we will use the `example-website` folder
95139

96140
### Set up DNS record
97141

@@ -100,7 +144,7 @@ Once your website is deployed, you will need a DNS Record to point to the file l
100144
* create a **hosted zone inside Route53** ([guide](https://medium.com/@dbclin/amazon-route-53-and-dns-whats-in-a-name-28fa4ac2826c)) on the AWS account you're using to deploy the website. In this scenario `webflow-aws` automatically manages the creation of all needed configuration, both for DNS Records and for SSL Certificate verification.
101145
* **[beta]** use a **custom DNS manager**, such as GoDaddy or your domain registrant. In this scenario, do not configure Route 53 properties and, once website is published, instructions with CNAMEs to set will be shown to you, so that you can manually configure them. Moreover, during first website deployment, you will need to publish a TXT record to verify your SSL Certificate.
102146

103-
With `webflow-aws` you can have one or more sub-domain point at your website, such as `example.com` and `www.example.com`.
147+
With `webflow-aws` you can have one or more subdomain point at your website, such as `example.com` and `www.example.com`.
104148

105149
In the `webflow-aws-config.yaml` file you will need to set the list of domains you would like to have your website pointing at. For example, you can have `example.com` and `www.example.com` enabled.
106150

@@ -167,16 +211,10 @@ Go inside the folder created before that contains:
167211
+ `webflow-aws-config.yaml` file
168212
+ `.zip` file
169213

170-
If it's the first time you are deploying it online, you have to call this command before:
171-
```bash
172-
webflow-aws setup
173-
```
174-
This command will create the Cloud Formation stack containing the support resources.
175-
176-
After this command, you can execute:
214+
To deploy your website, you have to execute this command:
177215

178216
```bash
179217
webflow-aws publish
180218
```
181219

182-
In 2 minutes, the content will be public available under the specified **domain names**.
220+
In 2 minutes, the content will be public available under the specified **domain names**.

dev-requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
bump2version~=1.0.1
2-
twine~=3.4.2
2+
twine~=4.0.2

requirements.txt

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,6 @@
1-
boto3~=1.16.46
2-
botocore~=1.19.46
3-
pyyaml~=5.3.1
4-
aws-cdk.core~=1.130.0
5-
aws-cdk.aws-certificatemanager~=1.130.0
6-
aws-cdk.aws-cloudfront~=1.130.0
7-
aws-cdk.aws-s3~=1.130.0
8-
aws-cdk.aws-s3-notifications~=1.130.0
9-
aws-cdk.aws-lambda~=1.130.0
10-
aws-cdk.aws-iam~=1.130.0
11-
aws-cdk.aws-cloudfront-origins~=1.130.0
12-
aws-cdk.aws-route53~=1.130.0
13-
aws-cdk.aws-route53-targets~=1.130.0
14-
Click~=7.1.2
15-
tqdm~=4.56.0
16-
emoji~=1.5.0
1+
boto3~=1.26.29
2+
pyyaml~=6.0
3+
aws-cdk-lib~=2.54.0
4+
Click~=8.1.3
5+
tqdm~=4.64.1
6+
emoji~=2.2.0

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# Inside of setup.cfg
22
[metadata]
3-
description-file = README.md
3+
description_file = README.md

setup.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from setuptools import setup, find_packages
1+
from setuptools import setup, find_namespace_packages
22

33
with open('requirements.txt') as f:
44
requirements = f.read().splitlines()
@@ -9,10 +9,10 @@
99
description='Deploy your Webflow static website on AWS',
1010
long_description=open('README.md').read(),
1111
long_description_content_type="text/markdown",
12-
author='CreateInCloud',
13-
author_email='[email protected]',
14-
url='https://github.com/CreateInCloud/webflow-aws',
15-
packages=find_packages(),
12+
author='odfdata',
13+
author_email='[email protected]',
14+
url='https://github.com/odfdata/webflow-aws',
15+
packages=find_namespace_packages(),
1616
python_requires='>=3.6',
1717
install_requires=requirements,
1818
include_package_data=True,

webflow_aws/app.py

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,21 @@
1-
import boto3
2-
from aws_cdk import core
1+
import aws_cdk as cdk
32

4-
from webflow_aws.create_cloudformation_template import WebflowAWSStack
5-
from webflow_aws.global_variables import AWS_REGION_NAME
6-
from webflow_aws.utils.base_utils import get_configuration, configuration_yaml_exists, setup_bucket_exists
3+
from webflow_aws.backend.component import Backend
4+
from webflow_aws.utils.base_utils import configuration_yaml_exists, get_configuration
75

6+
app = cdk.App()
87

9-
if __name__ == '__main__':
10-
if not configuration_yaml_exists:
11-
print('configuration.yaml file doesn\'t exist')
12-
exit()
13-
# check if the setup bucket exists
14-
configuration = get_configuration()
15-
session = boto3.session.Session(
16-
profile_name=configuration.get('aws_profile_name', 'default'), region_name=AWS_REGION_NAME)
17-
bucket_exists, webflow_aws_setup_bucket = setup_bucket_exists(
18-
aws_profile_name=configuration.get('aws_profile_name', 'default'), aws_region_name=AWS_REGION_NAME)
19-
if not bucket_exists:
20-
print(f'The bucket setup bucket doesn\'t exist. Run webflow-aws setup to create it')
21-
else:
22-
app = core.App()
23-
WebflowAWSStack(app, configuration['stack_name'], webflow_aws_setup_bucket, configuration)
24-
result = app.synth()
8+
if not configuration_yaml_exists:
9+
print('configuration.yaml file doesn\'t exist')
10+
exit()
11+
# load the configuration
12+
configuration = get_configuration()
13+
14+
Backend(
15+
app,
16+
configuration['stack_name'],
17+
configuration=configuration,
18+
env={"region": "us-east-1"}
19+
)
20+
21+
app.synth()

webflow_aws/backend/__init__.py

Whitespace-only changes.

webflow_aws/backend/component.py

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
from typing import List
2+
3+
from aws_cdk import (
4+
aws_cloudfront,
5+
aws_lambda,
6+
aws_route53,
7+
aws_route53_targets,
8+
aws_s3,
9+
aws_s3_notifications,
10+
Fn,
11+
Stack
12+
)
13+
from constructs import Construct
14+
15+
from webflow_aws.backend.compute.infrastructure import Compute
16+
from webflow_aws.backend.networking.infrastructure import Networking
17+
from webflow_aws.backend.storage.infrastructure import Storage
18+
19+
20+
class Backend(Stack):
21+
"""
22+
The backend AWS CDK app. It contains these sub-constructs:
23+
+ networking: contains all networking services used for WebflowAWS
24+
+ compute: contains all compute services used for WebflowAWS
25+
+ storage: contains all storage services used for WebflowAWS
26+
"""
27+
28+
def __init__(self, scope: Construct, construct_id: str, configuration: dict, **kwargs) -> None:
29+
super().__init__(scope, construct_id, **kwargs)
30+
self.networking = Networking(self, "WebflowAwsNetworking", configuration=configuration)
31+
self.compute = Compute(
32+
self, "WebflowAwsCompute", cloud_front_distribution=self.networking.main_cloud_front_distribution,
33+
configuration=configuration)
34+
self.storage = Storage(self, "WebflowAwsStorage", configuration=configuration)
35+
self.__add_s3_bucket_event_notification(
36+
s3_bucket=self.storage.s3_bucket, s3_trigger_lambda_function=self.compute.s3_trigger_lambda)
37+
self.__create_s3_trigger_lambda_invoke_permission(
38+
bucket_name=configuration['bucket_name'], s3_trigger_lambda_function=self.compute.s3_trigger_lambda)
39+
self.__create_s3_source_bucket_policy(
40+
s3_source_bucket=self.storage.s3_bucket,
41+
cloud_front_origin_access_identity=self.networking.cloud_front_origin_access_identity)
42+
self.__create_route_53_record_group(
43+
route_53_hosted_zone=self.networking.route_53_hosted_zone,
44+
domain_name=configuration['domain_name'],
45+
alternative_domain_names=configuration['CNAMEs'],
46+
cloud_front_distribution=self.networking.main_cloud_front_distribution)
47+
48+
@staticmethod
49+
def __add_s3_bucket_event_notification(
50+
s3_bucket: aws_s3.Bucket, s3_trigger_lambda_function: aws_lambda.Function
51+
):
52+
"""
53+
Add the S3 bucket event notification to trigger the AWS Lambda function every time a new object is created
54+
in the AWS S3 bucket inside the artifacts/ folder.
55+
56+
:param s3_bucket: The S3 bucket for which you want to create the event notification for
57+
:param s3_trigger_lambda_function: The AWS Lambda function you want to trigger
58+
"""
59+
s3_bucket.add_event_notification(
60+
aws_s3.EventType.OBJECT_CREATED,
61+
aws_s3_notifications.LambdaDestination(s3_trigger_lambda_function),
62+
(aws_s3.NotificationKeyFilter(prefix='artifacts/', suffix='.zip')))
63+
64+
def __create_route_53_record_group(
65+
self, route_53_hosted_zone: aws_route53.HostedZone, domain_name: str, alternative_domain_names: List[str],
66+
cloud_front_distribution: aws_cloudfront.Distribution
67+
):
68+
"""
69+
Create a new route 53 record group based on domain name and alternative domain names.
70+
71+
:param route_53_hosted_zone: the route 53 hosted zone you want to update
72+
:param domain_name: the domain name
73+
:param alternative_domain_names: the list of domain names you want to support
74+
:param cloud_front_distribution: the cloudfront distribution you want to point all the domains
75+
and subdomains to
76+
"""
77+
domain_names = alternative_domain_names
78+
domain_names.append(domain_name)
79+
[
80+
aws_route53.RecordSet(
81+
self,
82+
domain_name.replace('.', '').upper(),
83+
record_type=aws_route53.RecordType.A,
84+
zone=route_53_hosted_zone,
85+
record_name=domain_name,
86+
target=aws_route53.RecordTarget.from_alias(alias_target=aws_route53_targets.CloudFrontTarget(
87+
distribution=cloud_front_distribution
88+
))
89+
) for domain_name in set(domain_names)
90+
]
91+
92+
@staticmethod
93+
def __create_s3_source_bucket_policy(
94+
s3_source_bucket: aws_s3.Bucket,
95+
cloud_front_origin_access_identity: aws_cloudfront.OriginAccessIdentity
96+
):
97+
"""
98+
Create the S3 source bucket policy that allows the CDN to get files from the S3 bucket
99+
:param s3_source_bucket: the S3 source bucket you want to allow CDN to get files from
100+
:param cloud_front_origin_access_identity: the cloudfront origin access identity you want to allow
101+
bucket access for
102+
"""
103+
s3_source_bucket.grant_read(cloud_front_origin_access_identity)
104+
105+
def __create_s3_trigger_lambda_invoke_permission(
106+
self, bucket_name: str, s3_trigger_lambda_function: aws_lambda.Function
107+
):
108+
"""
109+
Create the permission to invoke the AWS lambda function from the S3 bucket
110+
:param bucket_name: the s3 bucket name from which the AWS Lambda function will be invoked
111+
:param s3_trigger_lambda_function: the AWS lambda function the bucket needs to have the permission to invoke
112+
"""
113+
aws_lambda.CfnPermission(
114+
self,
115+
'S3TriggerLambdaInvokePermission',
116+
function_name=s3_trigger_lambda_function.function_name,
117+
action='lambda:InvokeFunction',
118+
principal='s3.amazonaws.com',
119+
source_account=Fn.ref('AWS::AccountId'),
120+
source_arn=f'arn:aws:s3:::{bucket_name}'
121+
)

0 commit comments

Comments
 (0)