Skip to content

Commit 5ae86c6

Browse files
Merge branch 'master' of github.com:ModusCreateOrg/devops-infra-demo
2 parents d7da1ba + 38053dc commit 5ae86c6

File tree

13 files changed

+256
-52
lines changed

13 files changed

+256
-52
lines changed

Jenkinsfile

+98-26
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ import java.util.Random
1111

1212
// Set default variables
1313
final default_timeout_minutes = 20
14+
final codedeploy_target_skip = -1
15+
// See generally safe key names from https://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html
16+
final s3_safe_branch_name = env.BRANCH_NAME.replaceAll(/[^0-9a-zA-Z\!\-_\.\*\'\(\)]/ , "_")
17+
def codedeploy_target = codedeploy_target_skip
1418

1519
/** Set up CAPTCHA*/
1620
def get_captcha(Long hash_const) {
@@ -55,6 +59,25 @@ properties([
5559
defaultValue: false,
5660
description: 'Run Packer for this build?'
5761
),
62+
booleanParam(
63+
name: 'Package_CodeDeploy',
64+
defaultValue: false,
65+
description: 'Package CodeDeploy application on this build?'
66+
),
67+
string(
68+
name: 'Deploy_CodeDeploy',
69+
defaultValue: '',
70+
description: '''Deploy a CodeDeploy archive.
71+
Specify one of the following:
72+
1. "current" - deploy the CodeDeploy archive from this build
73+
2. a full S3 URL of a zip file to deploy
74+
3. an empty string (to skip deployment)'''
75+
),
76+
booleanParam(
77+
name: 'Skip_Terraform',
78+
defaultValue: false,
79+
description: 'Skip all Terraform steps, including validation and planning? (shortens cycle times when testing other aspects)'
80+
),
5881
booleanParam(
5982
name: 'Apply_Terraform',
6083
defaultValue: false,
@@ -84,7 +107,7 @@ properties([
84107
defaultValue: false,
85108
description: """Rotate server instances in Auto Scaling Group?
86109
You should do this if you changed ASG size or baked a new AMI.
87-
"""
110+
"""
88111
),
89112
booleanParam(
90113
name: 'Run_JMeter',
@@ -122,11 +145,11 @@ properties([
122145
stage('Preflight') {
123146

124147
// Check CAPTCHA
125-
def should_validate_captcha = params.Run_Packer || params.Apply_Terraform || params.Destroy_Terraform || params.Run_JMeter
148+
def should_validate_captcha = params.Run_Packer || params.Apply_Terraform || params.Destroy_Terraform || params.Run_JMeter || params.CodeDeploy_Target
126149

127150
if (should_validate_captcha) {
128151
if (params.CAPTCHA_Guess == null || params.CAPTCHA_Guess == "") {
129-
throw new Exception("No CAPTCHA guess detected, try again!")
152+
error "No CAPTCHA guess detected, try again!"
130153
}
131154
def guess = params.CAPTCHA_Guess as Long
132155
def hash = params.CAPTCHA_Hash as Long
@@ -137,6 +160,28 @@ stage('Preflight') {
137160
} else {
138161
echo "No CAPTCHA required, continuing"
139162
}
163+
164+
def build_number = env.BUILD_NUMBER as Long
165+
166+
switch (params.Deploy_CodeDeploy) {
167+
case "":
168+
echo "CodeDeploy deployment target is blank, skipping codedeploy step"
169+
break
170+
case "current":
171+
echo """CodeDeploy: targeting latest build
172+
CodeDeploy: Will use prefix ${s3_safe_branch_name}
173+
"""
174+
codedeploy_target = "current"
175+
break
176+
case ~/^s3:.*/:
177+
echo """CodeDeploy: targeting S3 URL build ${params.Deploy_CodeDeploy}"""
178+
codedeploy_target = params.Deploy_CodeDeploy
179+
break
180+
default:
181+
currentBuild.result = 'ABORTED'
182+
error "CodeDeploy build_number ${build_number} is not understood"
183+
break
184+
}
140185
}
141186

142187
stage('Checkout') {
@@ -153,8 +198,8 @@ stage('Validate') {
153198
node {
154199
wrap.call({
155200
unstash 'src'
156-
// Validate packer templates, check branch
157-
sh ("./bin/validate.sh")
201+
// Validate packer templates, check branch, lint shell scripts, lint terraform
202+
sh ("SKIP_TERRAFORM=${params.Skip_Terraform} ./bin/validate.sh")
158203
})
159204
}
160205
}
@@ -191,36 +236,40 @@ if (params.Run_Packer) {
191236
}
192237
}
193238

194-
stage('Build CodeDeploy Archive') {
195-
node {
196-
wrap.call({
197-
unstash 'src'
198-
sh ("./bin/build-codedeploy.sh")
199-
})
239+
if (params.Package_CodeDeploy) {
240+
stage('Package CodeDeploy Archive') {
241+
node {
242+
wrap.call({
243+
unstash 'src'
244+
sh ("./bin/build-codedeploy.sh ${s3_safe_branch_name}")
245+
})
246+
}
200247
}
201248
}
202249

203250
def terraform_prompt = 'Should we apply the Terraform plan?'
204251

205252

206-
stage('Plan Terraform') {
207-
node {
208-
wrap.call({
209-
unstash 'src'
210-
def verb = "plan"
211-
if (params.Destroy_Terraform) {
212-
verb += '-destroy';
213-
terraform_prompt += ' WARNING: will DESTROY resources';
214-
}
215-
sh ("""
216-
./bin/terraform.sh ${verb}
217-
""")
218-
})
219-
stash includes: "**", excludes: ".git/", name: 'plan'
253+
if (! params.Skip_Terraform) {
254+
stage('Plan Terraform') {
255+
node {
256+
wrap.call({
257+
unstash 'src'
258+
def verb = "plan"
259+
if (params.Destroy_Terraform) {
260+
verb += '-destroy';
261+
terraform_prompt += ' WARNING: will DESTROY resources';
262+
}
263+
sh ("""
264+
./bin/terraform.sh ${verb}
265+
""")
266+
})
267+
stash includes: "**", excludes: ".git/", name: 'plan'
268+
}
220269
}
221270
}
222271

223-
if (params.Apply_Terraform || params.Destroy_Terraform) {
272+
if (! params.Skip_Terraform && params.Apply_Terraform || params.Destroy_Terraform) {
224273
// See https://support.cloudbees.com/hc/en-us/articles/226554067-Pipeline-How-to-add-an-input-step-with-timeout-that-continues-if-timeout-is-reached-using-a-default-value
225274
def userInput = false
226275
try {
@@ -241,6 +290,29 @@ if (params.Apply_Terraform || params.Destroy_Terraform) {
241290
}
242291
}
243292

293+
if (params.Rotate_Servers) {
294+
stage('Rotate Servers') {
295+
node {
296+
wrap.call({
297+
unstash 'src'
298+
sh ("./bin/rotate-asg.sh infra-demo-asg")
299+
})
300+
}
301+
}
302+
}
303+
304+
if (params.Deploy_CodeDeploy) {
305+
stage('Deploy') {
306+
node {
307+
wrap.call({
308+
unstash 'src'
309+
sh ("./bin/deploy-codedeploy.sh ${codedeploy_target} ${s3_safe_branch_name}")
310+
})
311+
}
312+
}
313+
}
314+
315+
244316
if (params.Rotate_Servers) {
245317
stage('Rotate Servers') {
246318
node {

README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ See the branch [demo-20180926](https://github.com/ModusCreateOrg/devops-infra-de
1414

1515
See the branch [demo-20181205](https://github.com/ModusCreateOrg/devops-infra-demo/tree/demo-20181205) for the code for the demo for the [Ansible NYC talk _Ansible Image Bakeries: Best Practices & Pitfalls_](https://www.meetup.com/Ansible-NYC/events/256728741/). Slides from this presentation are on [SlideShare](https://www.slideshare.net/RichardBullingtonMcG/ansible-image-bakeries-best-practices-and-pitfalls).
1616

17-
See the branch [demo-20190130](https://github.com/ModusCreateOrg/devops-infra-demo/tree/demo-20180130) for the code for the demo for the [Big Apple DevOps talk _Monitoring and Alerting as code with Terraform and New Relic_](https://www.meetup.com/Big-Apple-DevOps/events/257744262/). Slides from this presentation are on [Slideshare](https://www.slideshare.net/RichardBullingtonMcG/monitoring-and-alerting-as-code-with-terraform-and-new-relic).
17+
See the branch [demo-20190130](https://github.com/ModusCreateOrg/devops-infra-demo/tree/demo-20190130) for the code for the demo for the [Big Apple DevOps talk _Monitoring and Alerting as code with Terraform and New Relic_](https://www.meetup.com/Big-Apple-DevOps/events/257744262/). Slides from this presentation are on [Slideshare](https://www.slideshare.net/RichardBullingtonMcG/monitoring-and-alerting-as-code-with-terraform-and-new-relic).
18+
19+
See the branch [demo-20191109](https://github.com/ModusCreateOrg/devops-infra-demo/tree/demo-20191l09) for the code for the demo for the [BSidesCT 2019 talk g Apple DevOps talk _Extensible DevSecOps pipelines with Jenkins, Docker, Terraform, and a kitchen sink full of scanners_](https://bsidesct.org/schedule/). Slides from this presentation are on
20+
[Slideshare](https://www.slideshare.net/RichardBullingtonMcG/extensible-devsecops-pipelines-with-jenkins-docker-terrraform-and-a-kitchen-sink-full-of-scanners)
1821

1922
Instructions
2023
------------

ansible/roles/cloudwatch-agent/files/config.json

+5
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@
6161
"file_path": "/var/log/nginx/error.log",
6262
"log_group_name": "nginx-error",
6363
"log_stream_name": "{instance_id}"
64+
},
65+
{
66+
"file_path": "/opt/codedeploy-agent/deployment-root/deployment-logs/codedeploy-agent-deployments.log",
67+
"log_group_name": "codedeploy",
68+
"log_stream_name": "{instance_id}"
6469
}
6570
]
6671
}

ansible/roles/scan-openscap/defaults/main.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@
33
build_dir: /app/build
44
output_file_html: /app/build/scan-xccdf-results.html
55
output_file_xml: /app/build/scan-xccdf-results.xml
6-
profile: C2S
6+
# Oh no! The old C2S profile is no longer available!
7+
profile: standard
78
xccdf_file: /usr/share/xml/scap/ssg/content/ssg-centos7-xccdf.xml

ansible/roles/scan-openscap/tasks/main.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
cd {{ build_dir }}
1919
# This will have a non-zero exit if any of the scans fail, so do not fail immediately on that
2020
set +e
21-
oscap xccdf eval --fetch-remote-resources --profile {{ profile }} --results {{ output_file_xml }} {{ xccdf_file }}
21+
oscap xccdf eval --profile {{ profile }} --results {{ output_file_xml }} {{ xccdf_file }}
2222
set -e
2323
oscap xccdf generate report {{ output_file_xml }} > {{ output_file_html }}
2424
args:

bin/activate-rvm.sh

+5
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@
22
# Activate rvm
33
# Source this to activate RVM
44

5+
# CodeDeploy has no HOME variable defined!
6+
HOME=${HOME:-/centos}
57
RVM_SH=${RVM_SH:-$HOME/.rvm/scripts/rvm}
68
RUBY_VERSION=${RUBY_VERSION:-2.6.3}
79

810
# rvm hates the bash options -eu
911

12+
echo -n "Activating RVM. HOME=$HOME id:"
13+
id -a
14+
1015
if [[ ! -f "$RVM_SH" ]]; then
1116
echo "Error: $0: RVM_SH $RVM_SH not found"
1217
exit 1

bin/build-codedeploy.sh

+23-5
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,34 @@ BUILD_DIR="$BASE_DIR/build"
1616
ANSIBLE_DIR="$BASE_DIR/ansible"
1717
APPLICTION_DIR="$BASE_DIR/application"
1818
SRC_DIR="$BASE_DIR/src"
19+
GAUNTLT_DIR="$BASE_DIR/gauntlt"
20+
21+
# Credit to http://stackoverflow.com/a/246128/424301
22+
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
23+
BASE_DIR="$DIR/.."
24+
25+
# shellcheck disable=SC1090
26+
. "$DIR/common.sh"
27+
#shellcheck disable=SC1090
28+
. "$BASE_DIR/env.sh"
29+
1930

2031
GIT_REV="$(git rev-parse --short HEAD)"
2132
BUILD_NUMBER=${BUILD_NUMBER:-0}
22-
ARCHIVE="codedeploy-$BUILD_NUMBER-$GIT_REV.zip"
33+
BRANCH_PREFIX=${1:-master}
34+
ARCHIVE="codedeploy-$BRANCH_PREFIX-$BUILD_NUMBER-$GIT_REV.zip"
2335
CONTAINERNAME=infra-demo
36+
# Thanks https://stackoverflow.com/questions/33791069/quick-way-to-get-aws-account-number-from-the-cli-tools
37+
AWS_ACCOUNT_ID=$(get_aws_account_id)
38+
BUCKET="codedeploy-$AWS_ACCOUNT_ID"
39+
S3_URL="s3://$BUCKET/$ARCHIVE"
2440

2541
echo "GIT_REV=$GIT_REV"
42+
echo "BRANCH_PREFIX=$BRANCH_PREFIX"
2643
echo "BUILD_NUMBER=$BUILD_NUMBER"
2744
echo "ARCHIVE=$ARCHIVE"
45+
echo "S3_URL=$S3_URL"
2846

29-
# Thanks https://stackoverflow.com/questions/33791069/quick-way-to-get-aws-account-number-from-the-cli-tools
30-
AWS_ACCOUNT_ID=$(aws sts get-caller-identity --output text --query 'Account')
31-
BUCKET="codedeploy-$AWS_ACCOUNT_ID"
32-
S3_URL="s3://$BUCKET/$ARCHIVE"
3347

3448
if [[ -d "$BUILD_DIR" ]]; then
3549
rm -rf "$BUILD_DIR"
@@ -52,8 +66,11 @@ SOURCES="$BASE_DIR/bin
5266
$ANSIBLE_DIR
5367
$APPLICTION_DIR
5468
$SRC_DIR
69+
$GAUNTLT_DIR
5570
$BASE_DIR/codedeploy/appspec.yml"
71+
echo "Copying sources into place"
5672
for src in $SOURCES; do
73+
echo cp -a "$src" "$BUILD_DIR"
5774
cp -a "$src" "$BUILD_DIR"
5875
done
5976

@@ -64,6 +81,7 @@ done
6481
bin \
6582
ansible \
6683
application \
84+
gauntlt \
6785
src \
6886
venv \
6987
socket

bin/codedeploy/AfterInstall.sh

+3
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,6 @@ source ${VENV_DIR}/bin/activate
4141
set -u
4242
newrelic-admin generate-config "${NEWRELIC_LICENSE_KEY}" "${NEWRELIC_CONFIG_DIR}/newrelic.ini.orig"
4343
sed 's/^app_name =.*$/app_name = Spin/' "${NEWRELIC_CONFIG_DIR}/newrelic.ini.orig" > "${NEWRELIC_CONFIG_DIR}/newrelic.ini"
44+
45+
echo /app directory:
46+
ls -laZ /app

bin/codedeploy/ValidateService.sh

+19
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ ${DEBUG:-false} && set -vx
1414
# and http://wiki.bash-hackers.org/scripting/debuggingtips
1515
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
1616

17+
GAUNTLT_RESULTS=/app/build/gauntlt-results.html
18+
# TODO: save this to S3 instead
19+
GAUNTLT_RESULTS_SAVE="/home/centos/$DEPLOYMENT_ID-gauntlt-results.html"
20+
1721
check_every() {
1822
local delay=${1:-}
1923
local host="http://localhost/"
@@ -25,4 +29,19 @@ check_every() {
2529
done
2630
}
2731

32+
echo "Checking web server availability"
2833
check_every 2
34+
35+
echo "Scanning with openscap and gauntlt"
36+
mkdir -p /app/build /app/ansible/tmp
37+
cat < /dev/null > "$GAUNTLT_RESULTS"
38+
chown -R centos:centos "$GAUNTLT_RESULTS" /app/build /app/ansible/tmp
39+
chmod 755 "$GAUNTLT_RESULTS" /app/build /app/ansible/tmp
40+
41+
set +e
42+
sudo -u centos HOME=/home/centos /app/bin/ansible.sh scan-openscap.yml scan-gauntlt.yml
43+
RETCODE=$?
44+
set -e
45+
cp "$GAUNTLT_RESULTS" "$GAUNTLT_RESULTS_SAVE"
46+
rm -rf /app/ansible/tmp /app/build
47+
exit "$RETCODE"

0 commit comments

Comments
 (0)