in lib/compute/jenkins-main-node.ts [150:362]
public static configElements(stackName: string, stackRegion: string, httpConfigProps: HttpConfigProps, oidcFederateProps: OidcFederateProps): InitElement[] {
return [
InitPackage.yum('curl'),
InitPackage.yum('wget'),
InitPackage.yum('unzip'),
InitPackage.yum('tar'),
InitPackage.yum('jq'),
InitPackage.yum('python3'),
InitPackage.yum('python3-pip.noarch'),
InitPackage.yum('git'),
InitPackage.yum('java-1.8.0-openjdk'),
InitPackage.yum('java-1.8.0-openjdk-devel'),
InitPackage.yum('openssl'),
InitPackage.yum('mod_ssl'),
// Jenkins install is done with yum by adding a new repo
InitCommand.shellCommand('wget -O /etc/yum.repos.d/jenkins-stable.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo'),
InitCommand.shellCommand('rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key'),
// The yum install must be triggered via shell command to ensure the order of execution
InitCommand.shellCommand('yum install -y jenkins-2.263.4'),
InitCommand.shellCommand('sleep 60'),
InitCommand.shellCommand(oidcFederateProps.runWithOidc
? 'amazon-linux-extras install epel -y && yum -y install xmlstarlet'
: 'echo not installing xmlstarlet as not running with OIDC'),
// Jenkins needs to be accessible for httpd proxy
InitCommand.shellCommand('sed -i \'s@JENKINS_LISTEN_ADDRESS=""@JENKINS_LISTEN_ADDRESS="127.0.0.1"@g\' /etc/sysconfig/jenkins'),
InitCommand.shellCommand(httpConfigProps.useSsl
// eslint-disable-next-line max-len
? `aws --region ${stackRegion} secretsmanager get-secret-value --secret-id ${httpConfigProps.sslCertContentsArn} --query SecretString --output text > ${JenkinsMainNode.CERTIFICATE_FILE_PATH}`
: 'echo useSsl is false, not creating cert file'),
InitCommand.shellCommand(httpConfigProps.useSsl
// eslint-disable-next-line max-len
? `aws --region ${stackRegion} secretsmanager get-secret-value --secret-id ${httpConfigProps.sslCertChainArn} --query SecretString --output text > ${JenkinsMainNode.CERTIFICATE_CHAIN_FILE_PATH}`
: 'echo useSsl is false, not creating cert-chain file'),
InitCommand.shellCommand(httpConfigProps.useSsl
// eslint-disable-next-line max-len
? `mkdir /etc/ssl/private/ && aws --region ${stackRegion} secretsmanager get-secret-value --secret-id ${httpConfigProps.sslCertPrivateKeyContentsArn} --query SecretString --output text > ${JenkinsMainNode.PRIVATE_KEY_PATH}`
: 'echo useSsl is false, not creating key file'),
// Local reverse proxy is used, see design for details
// https://quip-amazon.com/jjIKA6tIPQbw/ODFE-Jenkins-Production-Cluster-JPC-High-Level-Design#BeF9CAIwx3k
InitPackage.yum('httpd'),
// Configuration to proxy jenkins on :8080 -> :80
InitFile.fromString('/etc/httpd/conf.d/jenkins.conf',
httpConfigProps.useSsl
? `<VirtualHost *:80>
ServerAdmin webmaster@localhost
Redirect permanent / https://replace_url.com/
</VirtualHost>
<VirtualHost *:443>
SSLEngine on
SSLCertificateFile ${JenkinsMainNode.CERTIFICATE_FILE_PATH}
SSLCertificateKeyFile ${JenkinsMainNode.PRIVATE_KEY_PATH}
SSLCertificateChainFile ${JenkinsMainNode.CERTIFICATE_CHAIN_FILE_PATH}
ServerAdmin webmaster@localhost
ProxyRequests Off
ProxyPreserveHost On
AllowEncodedSlashes NoDecode
<Proxy *>
Order deny,allow
Allow from all
</Proxy>
ProxyPass / http://localhost:8080/ nocanon
ProxyPassReverse / http://localhost:8080/
ProxyPassReverse / https://replace_url.com/
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Port "443"
</VirtualHost>
<IfModule mod_headers.c>
Header unset Server
</IfModule>`
: `<VirtualHost *:80>
ServerAdmin webmaster@127.0.0.1
ProxyRequests Off
ProxyPreserveHost On
AllowEncodedSlashes NoDecode
<Proxy http://127.0.0.1:8080/>
Order deny,allow
Allow from all
</Proxy>
ProxyPass / http://127.0.0.1:8080/ nocanon
ProxyPassReverse / http://127.0.0.1:8080/
</VirtualHost>`),
// replacing the jenkins redirect url if the using ssl
InitCommand.shellCommand(httpConfigProps.useSsl
? `var=\`aws --region ${stackRegion} secretsmanager get-secret-value --secret-id ${httpConfigProps.redirectUrlArn} --query SecretString --output text\``
+ ' && sed -i "s,https://replace_url.com/,$var," /etc/httpd/conf.d/jenkins.conf'
: 'echo Not altering the jenkins url'),
InitCommand.shellCommand('systemctl start httpd'),
InitPackage.yum('amazon-cloudwatch-agent'),
CloudwatchAgent.asInitFile('/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json', {
agent: {
metrics_collection_interval: 60, // seconds between collections
logfile: '/opt/aws/amazon-cloudwatch-agent/logs/amazon-cloudwatch-agent.log',
omit_hostname: true,
debug: false,
},
metrics: {
namespace: `${stackName}/JenkinsMainNode`,
append_dimensions: {
// eslint-disable-next-line no-template-curly-in-string
InstanceId: '${aws:InstanceId}',
},
aggregation_dimensions: [[]], // Create rollups without instance id
metrics_collected: {
procstat: [
{
pattern: 'jenkins',
measurement: [
'cpu_usage',
'cpu_time_system',
'cpu_time_user',
'read_bytes',
'write_bytes',
'pid_count',
],
metrics_collection_interval: 10,
},
],
mem: {
measurement: [
{ name: 'available_percent', unit: Unit.PERCENT },
{ name: 'used_percent', unit: Unit.PERCENT },
{ name: 'mem_total', unit: Unit.BYTES },
],
metrics_collection_interval: 1, // capture every second
},
},
},
logs: {
logs_collected: {
files: {
collect_list: [
{
file_path: '/var/log/jenkins/jenkins.log',
log_group_name: 'JenkinsMainNode/var/log/jenkins/jenkins.log',
auto_removal: true,
log_stream_name: 'jenkins.log',
// 2021-07-20 16:15:55.319+0000 [id=868] INFO jenkins.InitReactorRunner$1#onAttained: Completed initialization
timestamp_format: '%Y-%m-%d %H:%M:%S.%f%z',
},
],
},
},
force_flush_interval: 15,
},
}),
InitCommand.shellCommand('/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a stop'),
// eslint-disable-next-line max-len
InitCommand.shellCommand('/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json -s'),
// start jenkins service to generate all the default files and folders of jenkins
// Does not use InitService.enable() because it initialises the service after the instance is launched
InitCommand.shellCommand('systemctl start jenkins'),
// Commands are fired one after the other but it does not wait for the command to complete.
// Therefore, sleep 60 seconds to wait for jenkins to start
// This allows jenkins to generate the secrets files used for auth in jenkins-cli APIs
InitCommand.shellCommand('sleep 60'),
// creating a default user:password file to use to authenticate the jenkins-cli
// eslint-disable-next-line max-len
InitCommand.shellCommand(`echo -n "admin:" > ${JenkinsMainNode.JENKINS_DEFAULT_ID_PASS_PATH} && cat /var/lib/jenkins/secrets/initialAdminPassword >> ${JenkinsMainNode.JENKINS_DEFAULT_ID_PASS_PATH}`),
// Download jenkins-cli from the local machine
InitCommand.shellCommand('wget -O "jenkins-cli.jar" http://localhost:8080/jnlpJars/jenkins-cli.jar'),
// install all the list of plugins from the list and restart (done in same command as restart is to be done after completion of install-plugin)
// eslint-disable-next-line max-len
InitCommand.shellCommand(`java -jar /jenkins-cli.jar -s http://localhost:8080 -auth @${JenkinsMainNode.JENKINS_DEFAULT_ID_PASS_PATH} install-plugin ${JenkinsPlugins.plugins.join(' ')} `
+ ` && java -jar jenkins-cli.jar -s http://localhost:8080 -auth @${JenkinsMainNode.JENKINS_DEFAULT_ID_PASS_PATH} restart`),
// Warning : any commands after this may be executed before the above command is complete
// Commands are fired one after the other but it does not wait for the command to complete.
// Therefore, sleep 60 seconds to wait for plugins to install and jenkins to start which is required for the next step
InitCommand.shellCommand('sleep 60'),
InitFile.fromFileInline('/var/lib/jenkins/jenkins.yaml', join(__dirname, '../../resources/jenkins.yaml')),
// If devMode is false, first line extracts the oidcFederateProps as json from the secret manager
// xmlstarlet is used to setup the securityRealm values for oidc by editing the jenkins' config.xml file
InitCommand.shellCommand(oidcFederateProps.runWithOidc
// eslint-disable-next-line max-len
? `var=\`aws --region ${stackRegion} secretsmanager get-secret-value --secret-id ${oidcFederateProps.oidcCredArn} --query SecretString --output text\` && `
+ 'xmlstarlet ed -L -d "/hudson/securityRealm" '
+ '-s /hudson -t elem -n securityRealm -v " " '
+ '-i //securityRealm -t attr -n "class" -v "org.jenkinsci.plugins.oic.OicSecurityRealm" '
+ '-i //securityRealm -t attr -n "plugin" -v "oic-auth@1.8" '
// eslint-disable-next-line max-len
+ `${this.oidcConfigFields().map((e) => ` -s /hudson/securityRealm -t elem -n ${e[0]} -v ${e[1] === 'replace' ? `"$(echo $var | jq -r ".${e[0]}")"` : `"${e[1]}"`}`).join(' ')}`
+ ' /var/lib/jenkins/config.xml'
: 'echo Not altering the jenkins config.xml when not running with OIDC'),
// reloading jenkins config file
InitCommand.shellCommand(oidcFederateProps.runWithOidc
? `java -jar /jenkins-cli.jar -s http://localhost:8080 -auth @${JenkinsMainNode.JENKINS_DEFAULT_ID_PASS_PATH} reload-configuration`
: 'echo not reloading jenkins config when not running with OIDC'),
];
}