Skip to content

Commit 807778e

Browse files
authored
Feat: add test and prod deployment environments (#149)
2 parents 34a537b + 3078893 commit 807778e

File tree

12 files changed

+224
-110
lines changed

12 files changed

+224
-110
lines changed

.github/workflows/deploy.yml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ defaults:
1515
run:
1616
shell: bash
1717

18+
concurrency:
19+
# this ternary operator-like expression gives us the name of the deployment environment (see https://docs.github.com/en/actions/learn-github-actions/expressions#example)
20+
# and ensures that only one deployment per environment is in progress at a time
21+
group: ${{ github.ref_type != 'tag' && 'dev' || contains(github.ref, '-rc') && 'test' || 'prod' }}
22+
cancel-in-progress: true
23+
1824
jobs:
1925
tests-ui:
2026
uses: ./.github/workflows/tests-ui.yml
@@ -28,6 +34,7 @@ jobs:
2834
deploy:
2935
runs-on: ubuntu-latest
3036
needs: [tests-ui, tests-pytest]
37+
environment: ${{ github.ref_type != 'tag' && 'dev' || contains(github.ref, '-rc') && 'test' || 'prod' }}
3138
permissions:
3239
packages: write
3340
id-token: write
@@ -80,13 +87,11 @@ jobs:
8087
sudo mv ./.tools/copilot /usr/local/bin/copilot
8188
8289
- name: Deploy web Service
83-
run: |
84-
copilot deploy --name web --env dev
90+
run: copilot deploy --name web --env ${{ github.environment }}
8591
working-directory: ./infra
8692

8793
- name: Deploy streamlit Service
88-
run: |
89-
copilot deploy --name streamlit --env dev
94+
run: copilot deploy --name streamlit --env ${{ github.environment }}
9095
working-directory: ./infra
9196

9297
release:

bin/start_aws.sh

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
#!/usr/bin/env bash
22
set -eu
33

4-
# S3 bucket name is injected by Copilot as an environment variable
5-
# since it was created via copilot storage init --name pems-db, the variable is 'PEMSDB_NAME'
6-
S3_BUCKET_NAME="$PEMSDB_NAME"
4+
# S3 bucket name (BUCKET_NAME) is injected by Copilot as an environment variable
5+
# in the service manifest
76
S3_FIXTURE_PATH="fixtures.json"
87

9-
echo "Downloading $S3_FIXTURE_PATH from bucket $S3_BUCKET_NAME"
10-
aws s3 cp "s3://${S3_BUCKET_NAME}/${S3_FIXTURE_PATH}" "${DJANGO_DB_FIXTURES}"
8+
echo "Downloading $S3_FIXTURE_PATH from bucket $BUCKET_NAME"
9+
aws s3 cp "s3://${BUCKET_NAME}/${S3_FIXTURE_PATH}" "${DJANGO_DB_FIXTURES}"
1110
echo "Download complete"
1211

1312
bin/setup.sh

infra/cloudformation/gh_actions.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@ Resources:
5858
- Sid: AssumeRole
5959
Effect: Allow
6060
Action: "sts:AssumeRole"
61-
Resource: "arn:aws:iam::715841364638:role/pems-dev-EnvManagerRole"
61+
Resource:
62+
- "arn:aws:iam::715841364638:role/pems-dev-EnvManagerRole"
63+
- "arn:aws:iam::715841364638:role/pems-test-EnvManagerRole"
64+
- "arn:aws:iam::715841364638:role/pems-prod-EnvManagerRole"
6265
- Sid: ListStackInstances
6366
Effect: Allow
6467
Action: "cloudformation:ListStackInstances"
@@ -67,6 +70,10 @@ Resources:
6770
Effect: Allow
6871
Action: "cloudformation:DescribeStacks"
6972
Resource: "arn:aws:cloudformation:us-west-2:715841364638:stack/StackSet-pems-infrastructure-c95edbbc-22a7-4239-a10b-7d73ba9344c4/45d26e70-31d1-11f0-a04a-0a0876def005"
73+
- Sid: UpdateStack
74+
Effect: Allow
75+
Action: "cloudformation:UpdateStack"
76+
Resource: "arn:aws:cloudformation:us-west-2:715841364638:stack/pems-github-actions/407a9060-575b-11f0-84e3-0a0aa26e756d"
7077
- Sid: GetAuthorizationToken
7178
Effect: Allow
7279
Action: "ecr:GetAuthorizationToken"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Parameters:
2+
VPCID: !Ref VPC
3+
PrivateSubnets: !Join [",", [!Ref PrivateSubnet1, !Ref PrivateSubnet2]]

infra/copilot/web/addons/postgres-web.yml renamed to infra/copilot/environments/addons/postgres.yml

Lines changed: 74 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4,63 +4,81 @@ Parameters:
44
Description: Your application's name.
55
Env:
66
Type: String
7-
Description: The environment name your service, job, or workflow is being deployed to.
8-
Name:
9-
Type: String
10-
Description: Your workload's name.
7+
Description: The name of the environment being deployed.
118
# Customize your Aurora Serverless cluster by setting the default value of the following parameters.
12-
postgreswebDBName:
9+
postgresDBName:
1310
Type: String
1411
Description: The name of the initial database to be created in the Aurora Serverless v2 cluster.
1512
Default: postgres
1613
# Cannot have special characters
1714
# Naming constraints: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_Limits.html#RDS_Limits.Constraints
15+
VPCID:
16+
Type: String
17+
Description: The ID of the VPC in which to create the Aurora Serverless v2 cluster.
18+
Default: ""
19+
PrivateSubnets:
20+
Type: String
21+
Description: The IDs of the private subnets in which to create the Aurora Serverless v2 cluster.
22+
Default: ""
23+
1824
Mappings:
19-
postgreswebEnvScalingConfigurationMap:
25+
postgresEnvScalingConfigurationMap:
2026
dev:
2127
"DBMinCapacity": 0.5 # AllowedValues: from 0.5 through 128
2228
"DBMaxCapacity": 8 # AllowedValues: from 0.5 through 128
2329

30+
prod:
31+
"DBMinCapacity": 0.5 # AllowedValues: from 0.5 through 128
32+
"DBMaxCapacity": 8 # AllowedValues: from 0.5 through 128
33+
34+
test:
35+
"DBMinCapacity": 0.5 # AllowedValues: from 0.5 through 128
36+
"DBMaxCapacity": 8 # AllowedValues: from 0.5 through 128
37+
2438
All:
2539
"DBMinCapacity": 0.5 # AllowedValues: from 0.5 through 128
2640
"DBMaxCapacity": 8 # AllowedValues: from 0.5 through 128
2741

2842
Resources:
29-
postgreswebDBSubnetGroup:
43+
postgresDBSubnetGroup:
3044
Type: "AWS::RDS::DBSubnetGroup"
3145
Properties:
32-
DBSubnetGroupDescription: Group of Copilot private subnets for Aurora Serverless v2 cluster.
33-
SubnetIds:
34-
!Split [",", { "Fn::ImportValue": !Sub "${App}-${Env}-PrivateSubnets" }]
35-
postgreswebSecurityGroup:
46+
DBSubnetGroupDescription: Group of private subnets for Aurora Serverless v2 cluster.
47+
SubnetIds: !Split [",", !Ref PrivateSubnets]
48+
49+
postgresWorkloadSecurityGroup:
3650
Metadata:
37-
"aws:copilot:description": "A security group for your workload to access the Aurora Serverless v2 cluster postgresweb"
51+
"aws:copilot:description": "A security group for one or more workloads to access the Aurora Serverless v2 cluster postgres"
3852
Type: "AWS::EC2::SecurityGroup"
3953
Properties:
40-
GroupDescription: !Sub "The Security Group for ${Name} to access Aurora Serverless v2 cluster postgresweb."
41-
VpcId:
42-
Fn::ImportValue: !Sub "${App}-${Env}-VpcId"
54+
GroupDescription: "The Security Group to access Aurora Serverless v2 cluster postgres."
55+
VpcId: !Ref VPCID
4356
Tags:
4457
- Key: Name
45-
Value: !Sub "copilot-${App}-${Env}-${Name}-Aurora"
46-
postgreswebDBClusterSecurityGroup:
58+
Value: !Sub "copilot-${App}-${Env}-Aurora"
59+
60+
postgresDBClusterSecurityGroup:
4761
Metadata:
48-
"aws:copilot:description": "A security group for your Aurora Serverless v2 cluster postgresweb"
62+
"aws:copilot:description": "A security group for your Aurora Serverless v2 cluster postgres"
4963
Type: AWS::EC2::SecurityGroup
5064
Properties:
5165
GroupDescription: The Security Group for the Aurora Serverless v2 cluster.
52-
SecurityGroupIngress:
53-
- ToPort: 5432
54-
FromPort: 5432
55-
IpProtocol: tcp
56-
Description: !Sub "From the Aurora Security Group of the workload ${Name}."
57-
SourceSecurityGroupId: !Ref postgreswebSecurityGroup
58-
VpcId:
59-
Fn::ImportValue: !Sub "${App}-${Env}-VpcId"
66+
VpcId: !Ref VPCID
6067
Tags:
6168
- Key: Name
62-
Value: !Sub "copilot-${App}-${Env}-${Name}-Aurora"
63-
postgreswebAuroraSecret:
69+
Value: !Sub "copilot-${App}-${Env}-Aurora"
70+
71+
postgresDBClusterSecurityGroupIngressFromWorkload:
72+
Type: AWS::EC2::SecurityGroupIngress
73+
Properties:
74+
Description: Ingress from one or more workloads in the environment.
75+
GroupId: !Ref postgresDBClusterSecurityGroup
76+
IpProtocol: tcp
77+
ToPort: 5432
78+
FromPort: 5432
79+
SourceSecurityGroupId: !Ref postgresWorkloadSecurityGroup
80+
81+
postgresAuroraSecret:
6482
Metadata:
6583
"aws:copilot:description": "A Secrets Manager secret to store your DB credentials"
6684
Type: AWS::SecretsManager::Secret
@@ -72,7 +90,7 @@ Resources:
7290
ExcludePunctuation: true
7391
IncludeSpace: false
7492
PasswordLength: 16
75-
postgreswebDBClusterParameterGroup:
93+
postgresDBClusterParameterGroup:
7694
Metadata:
7795
"aws:copilot:description": "A DB parameter group for engine configuration values"
7896
Type: "AWS::RDS::DBClusterParameterGroup"
@@ -81,17 +99,18 @@ Resources:
8199
Family: "aurora-postgresql16"
82100
Parameters:
83101
client_encoding: "UTF8"
84-
postgreswebDBCluster:
102+
103+
postgresDBCluster:
85104
Metadata:
86-
"aws:copilot:description": "The postgresweb Aurora Serverless v2 database cluster"
105+
"aws:copilot:description": "The postgres Aurora Serverless v2 database cluster"
87106
Type: "AWS::RDS::DBCluster"
88107
Properties:
89108
MasterUsername:
90109
!Join [
91110
"",
92111
[
93112
"{{resolve:secretsmanager:",
94-
!Ref postgreswebAuroraSecret,
113+
!Ref postgresAuroraSecret,
95114
":SecretString:username}}",
96115
],
97116
]
@@ -100,31 +119,31 @@ Resources:
100119
"",
101120
[
102121
"{{resolve:secretsmanager:",
103-
!Ref postgreswebAuroraSecret,
122+
!Ref postgresAuroraSecret,
104123
":SecretString:password}}",
105124
],
106125
]
107-
DatabaseName: !Ref postgreswebDBName
126+
DatabaseName: !Ref postgresDBName
108127
Engine: "aurora-postgresql"
109128
EngineVersion: "16.2"
110-
EnableHttpEndpoint: true # enable the Data API feature
111-
DBClusterParameterGroupName: !Ref postgreswebDBClusterParameterGroup
112-
DBSubnetGroupName: !Ref postgreswebDBSubnetGroup
129+
DBClusterParameterGroupName: !Ref postgresDBClusterParameterGroup
130+
DBSubnetGroupName: !Ref postgresDBSubnetGroup
113131
Port: 5432
114132
VpcSecurityGroupIds:
115-
- !Ref postgreswebDBClusterSecurityGroup
133+
- !Ref postgresDBClusterSecurityGroup
116134
ServerlessV2ScalingConfiguration:
117135
# Replace "All" below with "!Ref Env" to set different autoscaling limits per environment.
118136
MinCapacity:
119-
!FindInMap [postgreswebEnvScalingConfigurationMap, All, DBMinCapacity]
137+
!FindInMap [postgresEnvScalingConfigurationMap, All, DBMinCapacity]
120138
MaxCapacity:
121-
!FindInMap [postgreswebEnvScalingConfigurationMap, All, DBMaxCapacity]
122-
postgreswebDBWriterInstance:
139+
!FindInMap [postgresEnvScalingConfigurationMap, All, DBMaxCapacity]
140+
141+
postgresDBWriterInstance:
123142
Metadata:
124-
"aws:copilot:description": "The postgresweb Aurora Serverless v2 writer instance"
143+
"aws:copilot:description": "The postgres Aurora Serverless v2 writer instance"
125144
Type: "AWS::RDS::DBInstance"
126145
Properties:
127-
DBClusterIdentifier: !Ref postgreswebDBCluster
146+
DBClusterIdentifier: !Ref postgresDBCluster
128147
DBInstanceClass: db.serverless
129148
Engine: "aurora-postgresql"
130149
PromotionTier: 1
@@ -133,16 +152,21 @@ Resources:
133152
- !GetAZs
134153
Ref: AWS::Region
135154

136-
postgreswebSecretAuroraClusterAttachment:
155+
postgresSecretAuroraClusterAttachment:
137156
Type: AWS::SecretsManager::SecretTargetAttachment
138157
Properties:
139-
SecretId: !Ref postgreswebAuroraSecret
140-
TargetId: !Ref postgreswebDBCluster
158+
SecretId: !Ref postgresAuroraSecret
159+
TargetId: !Ref postgresDBCluster
141160
TargetType: AWS::RDS::DBCluster
161+
142162
Outputs:
143-
postgreswebSecret: # injected as POSTGRESWEB_SECRET environment variable by Copilot.
163+
postgresSecret:
144164
Description: "The JSON secret that holds the database username and password. Fields are 'host', 'port', 'dbname', 'username', 'password', 'dbClusterIdentifier' and 'engine'"
145-
Value: !Ref postgreswebAuroraSecret
146-
postgreswebSecurityGroup:
165+
Value: !Ref postgresAuroraSecret
166+
Export:
167+
Name: !Sub ${App}-${Env}-postgresAuroraSecret
168+
postgresSecurityGroup:
147169
Description: "The security group to attach to the workload."
148-
Value: !Ref postgreswebSecurityGroup
170+
Value: !Ref postgresWorkloadSecurityGroup
171+
Export:
172+
Name: !Sub ${App}-${Env}-postgresSecurityGroup

infra/copilot/web/addons/pems-db.yml renamed to infra/copilot/environments/addons/s3-web.yml

Lines changed: 17 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@ Parameters:
44
Description: Your application's name.
55
Env:
66
Type: String
7-
Description: The environment name your service, job, or workflow is being deployed to.
8-
Name:
9-
Type: String
10-
Description: Your workload's name.
7+
Description: The name of the environment being deployed.
8+
119
Resources:
12-
pemsdbBucket:
10+
s3webBucket:
1311
Metadata:
14-
"aws:copilot:description": "An Amazon S3 bucket to store and retrieve objects for pems-db"
12+
"aws:copilot:description": "An Amazon S3 bucket, s3-web, for storing and retrieving objects"
1513
Type: AWS::S3::Bucket
1614
Properties:
1715
VersioningConfiguration:
@@ -37,7 +35,7 @@ Resources:
3735
AbortIncompleteMultipartUpload:
3836
DaysAfterInitiation: 1
3937

40-
pemsdbBucketPolicy:
38+
s3webBucketPolicy:
4139
Metadata:
4240
"aws:copilot:description": "A bucket policy to deny unencrypted access to the bucket and its contents"
4341
Type: AWS::S3::BucketPolicy
@@ -51,43 +49,21 @@ Resources:
5149
Principal: "*"
5250
Action: "s3:*"
5351
Resource:
54-
- !Sub ${ pemsdbBucket.Arn}/*
55-
- !Sub ${ pemsdbBucket.Arn}
52+
- !Sub ${ s3webBucket.Arn}/*
53+
- !Sub ${ s3webBucket.Arn}
5654
Condition:
5755
Bool:
5856
"aws:SecureTransport": false
59-
Bucket: !Ref pemsdbBucket
60-
61-
pemsdbAccessPolicy:
62-
Metadata:
63-
"aws:copilot:description": "An IAM ManagedPolicy for your service to access the pems-db bucket"
64-
Type: AWS::IAM::ManagedPolicy
65-
Properties:
66-
Description: !Sub
67-
- Grants CRUD access to the S3 bucket ${Bucket}
68-
- { Bucket: !Ref pemsdbBucket }
69-
PolicyDocument:
70-
Version: "2012-10-17"
71-
Statement:
72-
- Sid: S3ObjectActions
73-
Effect: Allow
74-
Action:
75-
- s3:GetObject
76-
- s3:PutObject
77-
- s3:PutObjectACL
78-
- s3:PutObjectTagging
79-
- s3:DeleteObject
80-
- s3:RestoreObject
81-
Resource: !Sub ${ pemsdbBucket.Arn}/*
82-
- Sid: S3ListAction
83-
Effect: Allow
84-
Action: s3:ListBucket
85-
Resource: !Sub ${ pemsdbBucket.Arn}
57+
Bucket: !Ref s3webBucket
8658

8759
Outputs:
88-
pemsdbName:
60+
s3webName:
8961
Description: "The name of a user-defined bucket."
90-
Value: !Ref pemsdbBucket
91-
pemsdbAccessPolicy:
92-
Description: "The IAM::ManagedPolicy to attach to the task role"
93-
Value: !Ref pemsdbAccessPolicy
62+
Value: !Ref s3webBucket
63+
Export:
64+
Name: !Sub ${App}-${Env}-s3webBucketName
65+
s3webBucketARN:
66+
Description: "The ARN of the s3-web bucket."
67+
Value: !GetAtt s3webBucket.Arn
68+
Export:
69+
Name: !Sub ${App}-${Env}-s3webBucketARN

0 commit comments

Comments
 (0)