-
Notifications
You must be signed in to change notification settings - Fork 0
/
Jenkinsfile
294 lines (223 loc) · 11.1 KB
/
Jenkinsfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
// Jenkins Pipeline script executed when a change is detected in Github. This script runs the tests
// for all changes. If the change is to the 'production' branch, this script also packages the
// application, builds the Docker image, and deploys to AWS ECR.
pipeline {
// Default agent is any free agent.
agent any
parameters {
choice(name: 'deployTarget', choices: ['', 'Testing', 'Production'], description: 'Choose the AWS account to deploy to. If no account is selected, it will not be deployed to AWS. IMPORTANT: only the "production" branch can be deployed to the "Production" account.')
string(name: 'executionEnvironment', defaultValue: 'test', description: 'Enter the environment to create. This is used as a suffix for all components, and should be either "test", "prod", or a developer name (eg: "asmith").')
}
environment {
// The name of the application, specified here for consistency.
APP_NAME = 'ereefs-download-manager'
// Maven-related
// -------------
// The name Maven uses when packaging the Java app.
JAR_NAME = "${APP_NAME}-jar-with-dependencies.jar"
// AWS-related
// -----------
// Credential ID for deploying to AWS.
AWS_CREDENTIALS_ID_PROD = "jenkins-ereefs-prod-download_manager"
AWS_CREDENTIALS_ID_TEST = "jenkins-ereefs-test-download_manager"
// AWS CloudFormation Id for project.
AWS_CLOUD_FORMATION_STACKNAME_PREFIX = "downloadManager"
// The deployment target based on the users' selection.
AWS_DEPLOY_TARGET = "${params.deployTarget == 'Production' ? 'prod' : 'testing'}"
// S3 bucket for Lambda deployment.
AWS_LAMBDA_S3_DEPLOY_BUCKET = "aims-ereefs-private-${params.executionEnvironment}"
// Docker-related
// --------------
// The name of the Docker image that will be built to run the compiled app.
IMAGE_NAME = "ereefs-download_manager-${params.executionEnvironment}"
// AWS account ID depending on the target environment
// Parameters for connecting to the AWS ECR (container repository).
ECR_PROD_URL = "https://${EREEFS_AWS_PROD_ACCOUNT_ID}.dkr.ecr.${EREEFS_AWS_REGION}.amazonaws.com"
ECR_TEST_URL = "https://${EREEFS_AWS_TEST_ACCOUNT_ID}.dkr.ecr.${EREEFS_AWS_REGION}.amazonaws.com"
ECR_CREDENTIALS_PROD = "ecr:${EREEFS_AWS_REGION}:${AWS_CREDENTIALS_ID_PROD}"
ECR_CREDENTIALS_TEST = "ecr:${EREEFS_AWS_REGION}:${AWS_CREDENTIALS_ID_TEST}"
MAVEN_REPO = "/workspace/.m2_${params.deployTarget}/repository"
// Retrieve the credentials from the Credentials Manager in Jenkins, for accessing Github Packages.
GITHUB_PACKAGES_CREDENTIALS = credentials('github-packages')
}
stages {
// NOTE: Use "mvn -Dmaven.repo.local=${MAVEN_REPO} ..." to avoid creating a new Maven repository for each project
// Use Maven to build and test the app, archiving the results.
stage('Maven tests') {
when {
anyOf {
expression {
return params.deployTarget == 'Production' && env.BRANCH_NAME == 'production'
}
expression {
return params.deployTarget == 'Testing'
}
}
}
// Maven will be executed within it's Docker container.
agent {
docker {
image 'maven:3.6-alpine'
reuseNode true
}
}
// Run the tests (-B for non-interactive).
steps {
sh '''
mvn -settings maven-settings.xml -DGITHUB_USERNAME=$GITHUB_PACKAGES_CREDENTIALS_USR -DGITHUB_TOKEN=$GITHUB_PACKAGES_CREDENTIALS_PSW -Dmaven.repo.local=${MAVEN_REPO} -B clean test
'''
}
// Define the handlers for post-processing.
post {
// Always capture the test results.
always {
// Always archive the test results.
junit 'target/surefire-reports/*.xml'
}
}
}
// Use Maven to build and package the app. The resulting JAR file is stashed for use in
// the Docker build stage.
stage('Maven package') {
when {
anyOf {
expression {
return params.deployTarget == 'Production' && env.BRANCH_NAME == 'production'
}
expression {
return params.deployTarget == 'Testing'
}
}
}
// Maven will be executed within it's Docker container.
agent {
docker {
image 'maven:3.6-alpine'
reuseNode true
}
}
// Compile and package the app.
steps {
sh '''
mvn -B -settings maven-settings.xml -DGITHUB_USERNAME=$GITHUB_PACKAGES_CREDENTIALS_USR -DGITHUB_TOKEN=$GITHUB_PACKAGES_CREDENTIALS_PSW -Dmaven.repo.local=${MAVEN_REPO} -DbuildId=${JENKINS_BUILD_ID} -DskipTests=true package
'''
}
}
// Build the Docker image.
stage('Docker build') {
when {
anyOf {
expression {
return params.deployTarget == 'Production' && env.BRANCH_NAME == 'production'
}
expression {
return params.deployTarget == 'Testing'
}
}
}
steps {
script {
// Build the Docker image.
docker.build(IMAGE_NAME, "--build-arg JAR_NAME=${JAR_NAME} --force-rm .")
}
}
}
// Deploy the Docker image and update the CloudFormation Stack.
stage('Deploy to AWS "TEST" environment') {
when {
anyOf {
expression {
return params.deployTarget == 'Testing'
}
}
}
steps {
script {
// Make a Lambda deployment package.
zip zipFile: 'target/lambda/sns-listener-deploy.zip', dir: 'src/lambda/sns-listener'
// Generate the MD5 hash of the zip file
def md5sum = sh(script: "md5sum target/lambda/sns-listener-deploy.zip | cut -d' ' -f1", returnStdout: true).trim()
// Update the CloudFormation Stack.
withAWS(region: EREEFS_AWS_REGION, credentials: AWS_CREDENTIALS_ID_TEST) {
s3Upload(
bucket: "${AWS_LAMBDA_S3_DEPLOY_BUCKET}",
path: "deploy/download-manager/lambda/sns-listener-deploy-${md5sum}.zip", // Use the MD5 hash in the file name
file: "target/lambda/sns-listener-deploy.zip"
)
// Make sure uploaded file is available on S3
sleep(time: 5, unit: 'SECONDS')
cfnUpdate(
stack: "${AWS_CLOUD_FORMATION_STACKNAME_PREFIX}-${params.executionEnvironment}",
params: ["Environment=${params.executionEnvironment}", "EcrUserId=${AWS_CREDENTIALS_ID_TEST}", "LambdaMd5sum=${md5sum}"],
tags: ["deployTarget=${params.deployTarget}","executionEnvironment=${params.executionEnvironment}"],
file: 'cloudformation.yaml',
timeoutInMinutes: 10,
pollInterval: 5000
)
}
// Credentials for connecting to the AWS ECR repository.
docker.withRegistry(ECR_TEST_URL, ECR_CREDENTIALS_TEST) {
// Deploy the Docker image.
docker.image(IMAGE_NAME).push(BUILD_NUMBER)
docker.image(IMAGE_NAME).push("latest")
}
}
}
}
// Deploy the Docker image and update the CloudFormation Stack.
stage('Deploy to AWS "PRODUCTION" environment') {
when {
anyOf {
expression {
return params.deployTarget == 'Production' && env.BRANCH_NAME == 'production'
}
}
}
steps {
script {
// Make a Lambda deployment package.
zip zipFile: 'target/lambda/sns-listener-deploy.zip', dir: 'src/lambda/sns-listener'
// Generate the MD5 hash of the zip file
def md5sum = sh(script: "md5sum target/lambda/sns-listener-deploy.zip | cut -d' ' -f1", returnStdout: true).trim()
// Update the CloudFormation Stack.
withAWS(region: EREEFS_AWS_REGION, credentials: AWS_CREDENTIALS_ID_PROD) {
s3Upload(
bucket: "${AWS_LAMBDA_S3_DEPLOY_BUCKET}",
path: "deploy/download-manager/lambda/sns-listener-deploy-${md5sum}.zip", // Use the MD5 hash in the file name
file: "target/lambda/sns-listener-deploy.zip"
)
// Make sure uploaded file is available on S3
sleep(time: 5, unit: 'SECONDS')
cfnUpdate(
stack: "${AWS_CLOUD_FORMATION_STACKNAME_PREFIX}-${params.executionEnvironment}",
params: ["Environment=${params.executionEnvironment}", "EcrUserId=${AWS_CREDENTIALS_ID_PROD}", "LambdaMd5sum=${md5sum}"],
tags: ["deployTarget=${params.deployTarget}","executionEnvironment=${params.executionEnvironment}"],
file: 'cloudformation.yaml',
timeoutInMinutes: 10,
pollInterval: 5000
)
}
// Credentials for connecting to the AWS ECR repository.
docker.withRegistry(ECR_PROD_URL, ECR_CREDENTIALS_PROD) {
// Deploy the Docker image.
docker.image(IMAGE_NAME).push(BUILD_NUMBER)
docker.image(IMAGE_NAME).push("latest")
}
}
}
}
}
// Post-processing.
post {
cleanup {
sh'''
# Remove any Docker containers that are not in use.
docker container prune --force
# Remove any Docker images that are not in use.
docker image prune --force
# Remote any Docker networks that are not in use.
docker network prune --force
'''
}
}
}