Skip to content

Instantly share code, notes, and snippets.

@enriquemanuel
Last active August 21, 2021 21:54
Show Gist options
  • Save enriquemanuel/faf28a5c50105b90731d9cc435bbb488 to your computer and use it in GitHub Desktop.
Save enriquemanuel/faf28a5c50105b90731d9cc435bbb488 to your computer and use it in GitHub Desktop.
this is a serverless project that is used to launch an EC2 instance and configure Jenkins using JCASC plugin that is stored in a repo so its cloned and it gets copied to the EC2 accordingly
[DEFAULT]
instance_type = t3.xlarge
security_groups = sg-1234
iam_role = iam-role
subnet_id = subnet-id
target_group_arn = arn:<aws>:elasticloadbalancing:<region>:<accountid>:targetgroup/<id>
[ebs]
device_name = /dev/xvda
delete_on_termination = True
volume_size = 200
volume_type = gp2
volume_kms_key = aws/ebs
[github]
admins = <ids>
#!/bin/bash
set -e
# Defaults
aws_default_region="us-gov-west-1"
debug=true
jenkins_url="url"
tz="America/New_York"
echo "Update and install Jenkins..."
# Update system and install Jenkins
sudo yum -y update
sudo yum -y install java-1.8.0 java-1.8.0-openjdk-devel git jq
sudo yum -y remove java-1.7.0-openjdk
sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
sudo rpm --import https://pkg.jenkins.io/redhat/jenkins.io.key
# Install EFS
sudo yum install -y amazon-efs-utils
echo "Configuring AWS default for Jenkins"
# Configure awscli
sudo mkdir -p ~/.aws/
sudo cat >~/.aws/config <<EOL
[default]
region = $aws_default_region
output = json
EOL
# Insert secrets here
client_id=replace_client_id
client_secret=replace_client_secret
github_org_name=replace_github_org_name
github_admins='replace_github_admins'
admin_email=replace_admin_email
# Credentials
## Channels have # at the start, so we are escaping it here
slack_team_domain='replace_slack_team_domain'
slack_token='replace_slack_token'
slack_channel='\replace_slack_channel'
deploy_channel='\replace_deploy_channel'
alert_channel='\replace_alert_channel'
test_channel='\replace_test_channel'
github_api_token='replace_github_api_token'
new_relic_api_key='replace_new_relic_api_key'
echo "Installing and configuring Jenkins..."
# Jenkins key exists on our base image so it is already there
sudo yum -y install jenkins
# Configure timezone and other jenkins catches
sudo sed -i "s#-Djava.awt.headless=true#-Djava.awt.headless=true -Djenkins.install.runSetupWizard=false -Duser.timezone=$tz#" /etc/sysconfig/jenkins
# Install Jenkins Configuration as Code repo
git clone https://github.com/something/jcasc.git /tmp/jac/
sudo cp /tmp/jac/jcasc/* /var/lib/jenkins/
echo "Getting Availability Zone..."
# Get the az of the instance
az=$(curl http://169.254.169.254/latest/meta-data/placement/availability-zone)
if [[ $az == "us-gov-west-1a" ]]; then
nfsip="1a-nfs-ip"
elif [[ $az == "us-gov-west-1b" ]]; then
nfsip="1b-nfs-ip"
fi
# Configure the JCaC
sudo sed -i "s#<client_id>#$client_id#" /var/lib/jenkins/jenkins.yaml
sudo sed -i "s#<client_secret>#$client_secret#" /var/lib/jenkins/jenkins.yaml
sudo sed -i "s#<ip>#$jenkins_url/#" /var/lib/jenkins/jenkins.yaml
sudo sed -i "s#<admins>#$github_admins#" /var/lib/jenkins/jenkins.yaml
sudo sed -i "s#<github_org_name>#$github_org_name#" /var/lib/jenkins/jenkins.yaml
sudo sed -i "s#<admin_email>#$admin_email#" /var/lib/jenkins/jenkins.yaml
sudo sed -i "s#<aws_region>#$aws_default_region#" /var/lib/jenkins/jenkins.yaml
# Credentials
sudo sed -i "s#<jenkins.slack_team_domain>#$slack_team_domain#" /var/lib/jenkins/jenkins.yaml
sudo sed -i "s#<jenkins.slack_token>#$slack_token#" /var/lib/jenkins/jenkins.yaml
sudo sed -i "s#<jenkins.slack_channel>#$slack_channel#" /var/lib/jenkins/jenkins.yaml
sudo sed -i "s#<jenkins.deploy_channel>#$deploy_channel#" /var/lib/jenkins/jenkins.yaml
sudo sed -i "s#<jenkins.alert_channel>#$alert_channel#" /var/lib/jenkins/jenkins.yaml
sudo sed -i "s#<jenkins.test_channel>#$test_channel#" /var/lib/jenkins/jenkins.yaml
sudo sed -i "s#<devops.new_relic_api_key>#$new_relic_api_key#" /var/lib/jenkins/jenkins.yaml
sudo sed -i "s#<devops.github_api_token>#$github_api_token#" /var/lib/jenkins/jenkins.yaml
sudo sed -i "s#<devops.pd_api_token>#$pd_api_token#" /var/lib/jenkins/jenkins.yaml
sudo sed -i "s#<devops.vault_pass>#$vault_pass#" /var/lib/jenkins/jenkins.yaml
# Reset ownership and permissions
chown jenkins:jenkins /var/lib/jenkins
chown -R jenkins:jenkins /var/lib/jenkins/*
chmod 700 /var/lib/jenkins/install_plugins.sh
chmod 700 /var/lib/jenkins/jenkins.yaml
chmod 700 /var/lib/jenkins/plugins.txt
# Add Jenkins to the docker group
usermod -a -G docker jenkins
echo "Copy Jenkins private key and set permissions"
private_key_file_name="/home/jenkins/.ssh/kp.pem"
cat > $private_key_file_name <<- EOM
'replace_jenkins_private_key'
EOM
chown jenkins:jenkins $private_key_file_name
chmod 600 $private_key_file_name
echo "Mounting EFS..."
# Mount the EFS (this only is for the jobs directory in jenkins)
mkdir /var/lib/jenkins/jobs
chown -R jenkins:jenkins /var/lib/jenkins/jobs
mount -t efs -o tls,accesspoint=id id.efs.us-gov-west-1.amazonaws.com:/ /var/lib/jenkins/jobs
echo ""
echo "Copying the Seed Job & Init Scripts"
# Create workspace folder
seed_job_workspace="/var/lib/jenkins/jobs/seed-job/workspace"
[[ -d $seed_job_workspace ]] || mkdir -p $seed_job_workspace
# Copy seed job to the workspace
cp /var/lib/jenkins/seedJob.groovy $seed_job_workspace/seedJob.groovy
chown -R jenkins:jenkins /var/lib/jenkins/jobs/*
# Create the init.groovy.d folder for Jenkins
init_dir="/var/lib/jenkins/init.groovy.d"
[[ -d $init_dir ]] || mkdir -p $init_dir
cp /var/lib/jenkins/seedJobPreApproval.groovy $init_dir/seedJobPreApproval.groovy
cp /var/lib/jenkins/startSeedJob.groovy $init_dir/startSeedJob.groovy
chown -R jenkins:jenkins /var/lib/jenkins/init.groovy.d/
# Install plugins
for plugin in `cat /var/lib/jenkins/plugins.txt`; do
/var/lib/jenkins/install_plugins.sh $plugin;
done
sudo pip install boto3
sudo pip install virtualenv
# Auto start if server gets restarted
sudo chkconfig --add jenkins
echo "Starting Jenkins..."
# Start jenkins
sudo service jenkins start
import json
import boto3
from dateutil import parser
import credstash
import os
from datetime import datetime
import configparser
import logging
import time
from botocore.exceptions import WaiterError
import sys
def automate(event, context):
logging.basicConfig(format='%(asctime)s %(levelname)-8s %(message)s',
level=logging.INFO, datefmt='%Y-%m-%d %H:%M:%S')
# find base AMI
base_ami = find_base_ami()
config = configparser.ConfigParser()
config.read('files/config.ini')
instance_type = config['DEFAULT']['instance_type']
sgs = config['DEFAULT']['security_groups'].split(',')
subnet_id = config['DEFAULT']['subnet_id']
iam_role = config['DEFAULT']['iam_role']
target_group_arn = config['DEFAULT']['target_group_arn']
table_name = os.environ.get('CREDSTASH_TABLE')
# Jenkins configuration
client_id = credstash.getSecret("jenkins.new_github_client_id", table=table_name)
client_secret = credstash.getSecret("jenkins.new_github_client_secret", table=table_name)
github_org_name = credstash.getSecret("jenkins.github_org_name", table=table_name)
github_admins = config['github']['admins']
admin_email = credstash.getSecret("jenkins.admin_email", table=table_name)
# Jenkins Secrets
slack_team_domain = credstash.getSecret("jenkins.slack_team_domain", table=table_name)
slack_token = credstash.getSecret("jenkins.slack_token", table=table_name)
slack_channel = credstash.getSecret("jenkins.slack_channel", table=table_name)
deploy_channel = credstash.getSecret("jenkins.deploy_channel", table=table_name)
alert_channel = credstash.getSecret("jenkins.alert_channel", table=table_name)
test_channel = credstash.getSecret("jenkins.test_channel", table=table_name)
new_relic_api_key = credstash.getSecret("devops.new_relic_api_key", table=table_name)
github_api_token = credstash.getSecret("devops.github_api_token", table=table_name)
jenkins_private_key = credstash.getSecret("devops.app.kp", table=table_name)
file_n_path = "/tmp/init.sh"
# Write Jenkins key file to a file first and then use sed command to replace it in the init file
jenkins_private_key_path = "/tmp/jenkins.pem"
file = open(jenkins_private_key_path, "w")
file.write(jenkins_private_key + "\n")
file.close()
# move file to temporary location so we can edit it
# lambda files in the /tmp dir can be modified
os.system("cp files/init.sh {}".format(file_n_path))
# configuration
os.system("sed -i'.original' -e 's/replace_client_id/{}/' {}".format(client_id, file_n_path))
os.system("sed -i'.original' -e 's/replace_client_secret/{}/' {}".format(client_secret, file_n_path))
os.system("sed -i'.original' -e 's/replace_github_org_name/{}/' {}".format(github_org_name, file_n_path))
os.system("sed -i'.original' -e 's/replace_github_admins/{}/' {}".format(github_admins, file_n_path))
os.system("sed -i'.original' -e 's/replace_admin_email/{}/' {}".format(admin_email, file_n_path))
# secrets
os.system("sed -i'.original' -e 's/replace_slack_team_domain/{}/' {}".format(slack_team_domain, file_n_path))
os.system("sed -i'.original' -e 's/replace_slack_token/{}/' {}".format(slack_token, file_n_path))
os.system("sed -i'.original' -e 's/replace_slack_channel/{}/' {}".format(slack_channel, file_n_path))
os.system("sed -i'.original' -e 's/replace_deploy_channel/{}/' {}".format(deploy_channel, file_n_path))
os.system("sed -i'.original' -e 's/replace_alert_channel/{}/' {}".format(alert_channel, file_n_path))
os.system("sed -i'.original' -e 's/replace_test_channel/{}/' {}".format(test_channel, file_n_path))
os.system("sed -i'.original' -e 's/replace_new_relic_api_key/{}/' {}".format(new_relic_api_key, file_n_path))
os.system("sed -i'.original' -e 's/replace_github_api_token/{}/' {}".format(github_api_token, file_n_path))
os.system("sed -i'.original' -e '/replace_jenkins_private_key/r {}' -e '/replace_jenkins_private_key/d' {}".format(jenkins_private_key_path, file_n_path))
# get the modified user data
with open(file_n_path, 'r') as myfile:
user_data = myfile.read()
# create the instance
ec2 = boto3.client('ec2')
response = ec2.run_instances(
ImageId=base_ami,
InstanceType=instance_type,
SecurityGroupIds=sgs,
SubnetId=subnet_id,
UserData=user_data,
MinCount=1,
MaxCount=1,
IamInstanceProfile={ 'Name': iam_role },
BlockDeviceMappings=[
{
'DeviceName': config['ebs']['device_name'],
'Ebs': {
'DeleteOnTermination': config['ebs'].getboolean('delete_on_termination'),
'VolumeSize': int(config['ebs']['volume_size']),
'VolumeType': config['ebs']['volume_type'],
'Encrypted': True
}
},
]
)
instance_id = response['Instances'][0]['InstanceId']
# Sleep 1 minute in order for the user data script to finish on the instance
time.sleep(60)
logging.info('Successfully launched new instance: %s', instance_id)
old_instance_id = get_old_instance_id()
logging.info('Old instance ID: %s', old_instance_id)
tags = get_current_instance_tags()
# tag the instance
response = ec2.create_tags(
Resources=[
response['Instances'][0]['InstanceId']
],
Tags=tags
)
attach_instance_to_target_group(instance_id, old_instance_id, target_group_arn)
return instance_id
def attach_instance_to_target_group(instance_id, old_instance_id, target_group_arn):
elbv2 = boto3.client('elbv2', region_name="us-gov-west-1")
elbv2.register_targets(
TargetGroupArn=target_group_arn,
Targets=[
{
'Id': instance_id,
'Port': 8080
},
]
)
logging.info('Successfully attached instance ID %s to the ALB target group %s.' %
(instance_id, target_group_arn))
# Wait for instances to become healthy
logging.info(
'Waiting for the ALB target group to have all healthy instances before removing the old instance ID...')
try:
waiter = elbv2.get_waiter('target_in_service')
waiter.wait(
TargetGroupArn=target_group_arn,
WaiterConfig={
'Delay': 5,
'MaxAttempts': 300
},
Targets= [{'Id': instance_id, 'Port': 8080 }]
)
logging.info('New instances are healthy...')
logging.info('Deregistering old instances from the target group...')
elbv2.deregister_targets(
TargetGroupArn=target_group_arn,
Targets=[
{
'Id': old_instance_id,
'Port': 8080
},
]
)
# Sleep 20 seconds for the instance to deregister before terminating it
time.sleep(20)
# If waiter succeeded terminate the old instance
ec2 = boto3.resource('ec2')
ec2.instances.filter(InstanceIds=[old_instance_id]).terminate()
except WaiterError as we:
logging.error('Received Waiter error: %s' % we)
logging.info('New instances are not healthy...')
sys.exit(1)
def get_old_instance_id():
ec2 = boto3.client('ec2')
info = ec2.describe_instances(
Filters=[
{
'Name': 'tag:Name',
'Values': ['<app_name>']
},
{ 'Name': 'instance-state-name',
'Values': ['running']
}
]
)
return info['Reservations'][0]['Instances'][0]['InstanceId']
def get_current_instance_tags():
ec2 = boto3.client('ec2')
info = ec2.describe_instances(
Filters=[{
'Name': 'tag:Name',
'Values': ['app_name_ec2']
}]
)
tags = info['Reservations'][0]['Instances'][0]['Tags']
now = datetime.now()
date = now.strftime("%Y%m%d-%H%M%S")
for tag in tags:
if tag.get('Key') == 'deployment_id':
tags.pop(tags.index(tag))
tags.append(
{'Key': 'deployment_id', 'Value': 'deployment-id-{}'.format(date)})
return tags
def latest_image(list_of_images):
latest = None
for image in list_of_images:
if not latest:
latest = image
continue
if parser.parse(image['CreationDate']) > parser.parse(latest['CreationDate']):
latest = image
return latest
def find_base_ami():
ec2 = boto3.client('ec2')
filters = [ {
'Name': 'tag:app_group',
'Values': ['app_group']
},{
'Name': 'tag:app_project',
'Values': ['app_project']
},{
'Name': 'tag:type',
'Values': ['base-ami']
},{
'Name': 'tag:application',
'Values': ['base-ami']
}]
response = ec2.describe_images(Filters=filters)
latest=latest_image(response['Images'])
return latest['ImageId']
# root
jenkins:
systemMessage: "Automating Configuration Devops Jenkins"
securityRealm:
github:
githubWebUri: "https://github.com"
githubApiUri: "https://api.github.com"
clientID: "<client_id>"
clientSecret: "<client_secret>"
oauthScopes: "read:org"
agentProtocols:
- "JNLP4-connect"
- "Ping"
authorizationStrategy:
github:
adminUserNames: "<admins>"
allowAnonymousJobStatusPermission: true
allowAnonymousReadPermission: true
allowCcTrayPermission: false
allowGithubWebHookPermission: true
authenticatedUserCreateJobPermission: false
authenticatedUserReadPermission: true
organizationNames: "<github_org_name>"
useRepositoryPermissions: true
disableRememberMe: true
mode: NORMAL
primaryView:
all:
name: "all"
quietPeriod: 5
scmCheckoutRetryCount: 0
views:
- all:
name: "all"
globalNodeProperties:
- envVars:
env:
- key: "AWS_DEFAULT_REGION"
value: "<aws_region>"
- key: "PATH"
value: "/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/opt/aws/bin:/home/dsva/.local/bin:/home/bin"
labelString: "deploy devops"
mode: NORMAL
numExecutors: 16
primaryView:
all:
name: "all"
quietPeriod: 5
scmCheckoutRetryCount: 0
#root
credentials:
system:
domainCredentials:
- credentials:
- string:
scope: GLOBAL
id: "SLACK_TEAM_DOMAIN"
secret: "<jenkins.slack_team_domain>"
description: "DSVA team on Slack"
- string:
scope: GLOBAL
id: "SLACK_TOKEN"
secret: "<jenkins.slack_token>"
description: "Slack token"
- string:
scope: GLOBAL
id: "DEPLOY_SLACK_TOKEN"
secret: "<jenkins.slack_token>"
description: "Deploy Slack token"
- string:
scope: GLOBAL
id: "ALERT_SLACK_TOKEN"
secret: "<jenkins.slack_token>"
description: "Alert Slack Token"
- string:
scope: GLOBAL
id: "TEST_SLACK_TOKEN"
secret: "<jenkins.slack_token>"
description: "Test Slack token"
- string:
scope: GLOBAL
id: "SLACK_CHANNEL"
secret: "<jenkins.slack_channel>"
description: "Regular Slack Channel"
- string:
scope: GLOBAL
id: "DEPLOY_CHANNEL"
secret: "<jenkins.deploy_channel>"
description: "Deploy Slack Channel"
- string:
scope: GLOBAL
id: "ALERT_SLACK_CHANNEL"
secret: "<jenkins.alert_channel>"
description: "Alert Slack Channel"
- string:
scope: GLOBAL
id: "TEST_SLACK_CHANNEL"
secret: "<jenkins.test_channel>"
description: "Test Slack Channel"
- string:
scope: GLOBAL
id: "NEW_RELIC_API_KEY"
secret: "<devops.new_relic_api_key>"
description: "New Relic API Key"
- usernamePassword:
scope: GLOBAL
id: "va-bot"
username: "va-bot"
password: "<devops.github_api_token>"
description: "va-bot username/password"
- string:
scope: GLOBAL
id: "GIT_CREDENTIAL"
secret: "<devops.github_api_token>"
description: "va-bot personal access token"
# root
tool:
git:
installations:
- name: git
home: /usr/bin/git
# root
unclassified:
location:
adminAddress: "<admin_email>"
url: "http://<ip>"
slackNotifier:
teamDomain: "dsva"
baseUrl: ""
tokenCredentialId: "SLACK_TOKEN"
globalLibraries:
libraries:
- name: "devops-jenkins"
defaultVersion: "master"
implicit: true
retriever:
modernSCM:
scm:
git:
remote: "https://github.com/lalalala/-devops-jenkins.git"
credentialsId: "va-bot"
# root
jobs:
- script: >
job('seed-job'){
displayName('seed-job')
logRotator {
numToKeep(15)
}
wrappers {
credentialsBinding {
string('GIT_CREDENTIAL', 'GIT_CREDENTIAL')
}
}
steps {
dsl(['seedJob.groovy'])
}
parameters {
stringParam('DEPLOYMENT_DEV_BRANCH', 'master', 'appeals-deployment branch')
}
triggers {
cron('H H(0-5) * * *')
}
}
- script: >
queue('seed-job')
workflow-aggregator
blueocean
configuration-as-code
job-dsl
git-parameter
github-oauth
slack
ws-cleanup
credentials
configuration-as-code-support
envinject
<?xml version='1.0' encoding='UTF-8'?>
<scriptApproval plugin="script-security">
<approvedSignatures>
<string>method org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper getRawBuild</string>
<string>method hudson.model.Cause getShortDescription</string>
<string>method hudson.model.Run getCauses</string>
<string>method hudson.model.Run getDurationString</string>
<string>method hudson.plugins.git.BranchSpec getName</string>
<string>method hudson.plugins.git.GitSCM getBranches</string>
<string>method java.lang.Process waitFor</string>
<string>method java.util.Random nextInt int</string>
<string>method org.kohsuke.github.GHIssue comment java.lang.String</string>
<string>method org.kohsuke.github.GHIssue getNumber</string>
<string>method org.kohsuke.github.GHPullRequest getMergeable</string>
<string>method org.kohsuke.github.GHPullRequest getMergeableState</string>
<string>method org.kohsuke.github.GHPullRequest listCommits</string>
<string>method org.kohsuke.github.GHPullRequest merge java.lang.String</string>
<string>method org.kohsuke.github.GHPullRequestCommitDetail getCommit</string>
<string>method org.kohsuke.github.GHPullRequestCommitDetail$Commit getAuthor</string>
<string>method org.kohsuke.github.GHRef getObject</string>
<string>method org.kohsuke.github.GHRef$GHObject getSha</string>
<string>method org.kohsuke.github.GHRepository createPullRequest java.lang.String java.lang.String java.lang.String java.lang.String</string>
<string>method org.kohsuke.github.GHRepository createRef java.lang.String java.lang.String</string>
<string>method org.kohsuke.github.GHRepository getPullRequest int</string>
<string>method org.kohsuke.github.GHRepository getRef java.lang.String</string>
<string>method org.kohsuke.github.GitHub getUser java.lang.String</string>
<string>method org.kohsuke.github.GitUser getEmail</string>
<string>new java.util.Date</string>
<string>new java.util.Random</string>
<string>staticMethod groovy.json.JsonOutput toJson java.lang.Object</string>
<string>staticMethod java.net.URLDecoder decode java.lang.String</string>
<string>staticMethod org.codehaus.groovy.runtime.DefaultGroovyMethods get java.util.Map java.lang.Object java.lang.Object</string>
<string>staticMethod org.codehaus.groovy.runtime.DefaultGroovyMethods minus java.lang.String java.lang.Object</string>
<string>staticMethod org.codehaus.groovy.runtime.DefaultGroovyMethods stripIndent java.lang.String</string>
<string>staticMethod org.codehaus.groovy.runtime.DefaultGroovyMethods stripMargin java.lang.String</string>
<string>staticMethod org.codehaus.groovy.runtime.ProcessGroovyMethods getText java.lang.Process</string>
<string>staticMethod org.codehaus.groovy.runtime.ScriptBytecodeAdapter createRange java.lang.Object java.lang.Object boolean</string>
<!-- For review_instance_deploy. TODO: evaluate custom Jenkins plugin -->
<string>staticField org.kohsuke.github.GHDeploymentState ERROR</string>
<string>staticField org.kohsuke.github.GHDeploymentState SUCCESS</string>
<string>staticMethod org.kohsuke.github.GitHub connect</string>
<string>staticMethod org.codehaus.groovy.runtime.EncodingGroovyMethods encodeHex byte[]</string>
<string>staticMethod java.security.MessageDigest getInstance java.lang.String</string>
<string>method groovy.lang.GString getBytes</string>
<string>method java.security.MessageDigest digest byte[]</string>
<string>method org.kohsuke.github.GHRepository createDeployment java.lang.String</string>
<string>method org.kohsuke.github.GHDeploymentBuilder autoMerge boolean</string>
<string>method org.kohsuke.github.GHDeploymentBuilder environment java.lang.String</string>
<string>method org.kohsuke.github.GHDeploymentBuilder requiredContexts java.util.List</string>
<string>method org.kohsuke.github.GHDeploymentBuilder create</string>
<string>method org.kohsuke.github.GitHub getRepository java.lang.String</string>
<string>method org.kohsuke.github.GHObject getId</string>
<string>method org.kohsuke.github.GHRepository createDeployStatus int org.kohsuke.github.GHDeploymentState</string>
<string>method org.kohsuke.github.GHDeploymentStatusBuilder targetUrl java.lang.String</string>
<string>method org.kohsuke.github.GHDeploymentStatusBuilder create</string>
<string>method org.kohsuke.github.GHDeploymentStatus getTargetUrl</string>
<!-- /review_instance_deploy -->
<!-- For scorecard_builds -->
<string>method org.kohsuke.github.GHRef delete</string>
<!-- /scorecard_builds -->
</approvedSignatures>
<aclApprovedSignatures/>
<approvedClasspathEntries/>
<pendingScripts/>
<pendingSignatures/>
<pendingClasspathEntries/>
</scriptApproval>
@Grab('org.yaml:snakeyaml:1.17')
import groovy.lang.GroovyClassLoader
import groovy.transform.Field
import org.yaml.snakeyaml.Yaml
@Field seedJobWorkspace = "/var/lib/jenkins/jobs/seed-job/workspace/"
@Field workspaceDir = new File(seedJobWorkspace)
@Field repoPath = seedJobWorkspace + "deployment"
@Field jobDefDir = new File(repoPath + "/jobdefs")
@Field classLoader = new GroovyClassLoader(getClass().getClassLoader())
def deploymentBranch
def checkout() {
def jenkinsRepo = "https://" + GIT_CREDENTIAL + "@github.com/lalala/deployment.git"
try {
deploymentBranch = "${DEPLOYMENT_DEV_BRANCH}"
}
catch(Exception ex){
deploymentBranch = "master"
}
println("Cloning deployment repo with branch ${deploymentBranch}...")
def gitProc = ["git", "clone", "-b", deploymentBranch, jenkinsRepo].execute(null, workspaceDir)
def out = new StringBuffer()
def err = new StringBuffer()
gitProc.consumeProcessOutput(out, err)
gitProc.waitForOrKill(10*60*1000) // 10 minutes
println(out)
println(err)
def exitCode = gitProc.exitValue()
if (exitCode != 0) {
println("git exited with code: ${exitCode}")
throw new Exception("git process exit code was ${exitCode}")
}
}
def createFolderFromYaml(String folderName, File yamlFile) {
Yaml parser = new Yaml()
def metadata = parser.load(yamlFile.text)
println("Creating Folder... $folderName")
folder(folderName) {
displayName(metadata['displayName'] ?: "")
description(metadata['description'] ?: "")
}
}
def createFolder(String folderName, String folderFullName) {
println("Creating folder: $folderName")
folder(folderFullName) {
displayName(folderName)
}
}
def createJobFromGroovy(String folderName, File groovyFile) {
println("Creating Job... $groovyFile.name")
GroovyShell shell = new GroovyShell(classLoader, this.binding)
def script = shell.parse(groovyFile)
def arguments = [:]
arguments['folderName'] = folderName
arguments['jenkins'] = this
script.invokeMethod("createJob", arguments)
}
def scanFolder(File folder, String parentFolderName) {
def folderName = parentFolderName + "/" + folder.getName()
File folderFile = new File(folder.absolutePath + "/folder.yml")
// Create Jenkins folders
if(folderFile.exists()) {
createFolderFromYaml(folderName, folderFile)
}
else {
createFolder(folder.getName(), folderName)
}
// Process the rest of the folders in this directory
for (file in folder.listFiles()) {
if(file.isDirectory()) {
scanFolder(file, folderName)
}
else {
if (file.getName().toLowerCase().endsWith("job.groovy")) {
// Run all the *job.groovy scripts
createJobFromGroovy(folderName, file)
}
}
}
}
def scanRootFolder(File folder) {
println("Scanning root folder")
for (file in folder.listFiles()) {
if(file.isDirectory()) {
scanFolder(file, "")
}
}
}
// clean up the appeals deployment repo to make sure we have a clean start
["rm", "-rf", repoPath].execute().waitFor()
checkout()
// Add jobdefs dir to classpath in classLoaders used to run jobdef files
// This allows the scripts to import the common package under this directory
classLoader.addClasspath(jobDefDir.getAbsolutePath())
// Start scanning for jobdef files
scanRootFolder(jobDefDir)
import jenkins.model.Jenkins
import jenkins.security.s2m.AdminWhitelistRule
import org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval;
import org.jenkinsci.plugins.scriptsecurity.scripts.languages.GroovyLanguage;
import jenkins.AgentProtocol
// Disable deprecated JNLP protocols
def protocols = AgentProtocol.all()
protocols.each { protocol ->
if(protocol.name && (protocol.name.contains("JNLP-connect") || protocol.name.contains("JNLP2-connect"))) {
protocols.remove(protocol)
jnlpChanged = true
println "Jenkins deprecated protocol ${protocol.name} has been disabled."
}
}
// Jenkins is noisy about this, even though it's not relevant to our situation
Jenkins.instance.getInjector()
.getInstance(AdminWhitelistRule.class)
.setMasterKillSwitch(false)
ScriptApproval.get().preapprove(
new File('/var/lib/jenkins/jobs/seed-job/workspace/seedJob.groovy').getText('UTF-8'),
GroovyLanguage.get()
)
service: jenkins
frameworkVersion: ">=1.0.0 <2.0.0"
package:
individually: true
exclude:
- .git/**
- lib/**
- .venv/**
- .venvdev/**
- .vscode/**
- __pycache__/**
custom:
pythonRequirements:
dockerizePip: true
provider:
name: aws
runtime: python3.6
region: us-gov-west-1
stage: ${opt:stage, 'utility'}
logRetentionInDays: 5
memorySize: 128
role: arn:aws-us-gov:iam::<accountid>:role/role
endpointType: regional
vpc:
securityGroupIds:
- sg-id
subnetIds:
- subnet-id
environment:
CREDSTASH_TABLE: "table-credstash"
stackTags:
team: "teamtags"
dev: "devops"
Environment: "utility"
functions:
deploy:
handler: jenkins.automate
timeout: 900
layers:
- arn:aws-us-gov:lambda:us-gov-west-1:<accountid>:layer:credstashLayer:5
def job = hudson.model.Hudson.instance.getItemByFullName('seed-job')
hudson.model.Hudson.instance.queue.schedule(job, 0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment