Skip to content

Commit

Permalink
Merge pull request #7 from tmcsantos/BACKLOG-23041
Browse files Browse the repository at this point in the history
[Backlog-23041] configures jenkins to enforce job namings
  • Loading branch information
hbfernandes authored May 4, 2018
2 parents da39068 + e5fff6f commit 3a1a632
Show file tree
Hide file tree
Showing 12 changed files with 247 additions and 42 deletions.
1 change: 1 addition & 0 deletions docker/jenkins/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
credentials
2 changes: 1 addition & 1 deletion docker/jenkins/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# https://github.com/jenkinsci/docker/blob/master/README.md
FROM jenkins/jenkins:lts

ENV CREDENTIALS_ID=github-buildguy
ENV CREDENTIALS_ID github-buildguy

ENV JAVA_OPTS -Djenkins.install.runSetupWizard=false

Expand Down
21 changes: 6 additions & 15 deletions docker/jenkins/Dockerfile-alpine
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,15 @@ FROM jenkins/jenkins:lts-alpine

USER root

ENV GLIBC_VERSION=2.27-r0
ENV CREDENTIALS_ID=github-buildguy
ENV CREDENTIALS_ID github-buildguy
ENV JAVA_OPTS -Djenkins.install.runSetupWizard=false

# maven-surefire-plugin fails on Docker and Alpine, the version 2.20.1 changed how the plugin interacts with processes
# workarounds are to downgrade to 2.20 or install procps

RUN apk --no-cache add --update ca-certificates procps && \
wget -q -O /etc/apk/keys/sgerrand.rsa.pub https://raw.githubusercontent.com/sgerrand/alpine-pkg-glibc/master/sgerrand.rsa.pub && \
wget -q https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VERSION}/glibc-${GLIBC_VERSION}.apk && \
wget -q https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VERSION}/glibc-bin-${GLIBC_VERSION}.apk && \
wget -q https://github.com/sgerrand/alpine-pkg-glibc/releases/download/${GLIBC_VERSION}/glibc-i18n-${GLIBC_VERSION}.apk && \
apk add glibc-${GLIBC_VERSION}.apk glibc-bin-${GLIBC_VERSION}.apk glibc-i18n-${GLIBC_VERSION}.apk && \
/usr/glibc-compat/bin/localedef -i en_US -f UTF-8 en_US.UTF-8 && \
echo "export LANG=en_US.UTF-8" > /etc/profile.d/locale.sh && \
# cleaning caches
rm -rf *.apk \
/var/cache/apk/*
# workaround is to install procps
RUN apk --no-cache add --update procps fontconfig

# adding dynamic ELFs required by PhantomJS, and other glibc dependent apps like java
ADD alpine/tools/dockerized-phantomjs.tgz /

USER jenkins

Expand Down
19 changes: 17 additions & 2 deletions docker/jenkins/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,29 @@ Edit `secrets/credentials` file with the necessary credentials, and run the `go.
./go.sh
```

This will build/start a fully configured jenkins container.
This will build/start a fully configured jenkins container.\
You can now point your browser to [0.0.0.0:8080](http://0.0.0.0:8080) and start using.

Alternatively you can build the ***alpine*** version.

```
./go.sh -v alpine
```

NOTE: This script automatically creates a *jenkins_pipeline* volume on docker host, that will survive container start/stop/deletion.
NOTE: This script automatically creates a *jenkins_pipeline* volume on docker host, that will survive container start/stop/deletion.

```
./go.sh -h
usage: [options]
options:
-h, --help This help message
-v, --variant string Sets the variant of the jenkins container.
--debug Enable debug mode, this will only print the commands that will be run.
-q, --quiet Enable quiet mode.
-d, --daemon Run in daemon mode.
-n, --no-build Skip the building part.
-f, --force Force building from the start.
```

# Manual usage

Expand Down
2 changes: 2 additions & 0 deletions docker/jenkins/alpine/tools/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.tgz
*.tar.gz
12 changes: 12 additions & 0 deletions docker/jenkins/alpine/tools/Dockerfile.phantomjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM ubuntu:18.04

ENV PHANTOMJS_VERSION 2.1.1

RUN apt-get update -qq && \
apt-get -qy install ca-certificates rsync curl libfontconfig python python-pip python-setuptools && \
curl -SL https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-${PHANTOMJS_VERSION}-linux-x86_64.tar.bz2 | tar xj -C /usr/local --strip-components=1 && \
pip install dockerize

ADD pack_libs.sh /

CMD ["sh", "-c", "/pack_libs.sh"]
16 changes: 16 additions & 0 deletions docker/jenkins/alpine/tools/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Phantomjs docker build

Because alpine uses musl, some apps that are dynamicaly linked to glibc will not run.
Java and Phantomjs are such tools we use that are linked to glibc.

In this docker image, we'll build and extract the minimal required libs to be able to run such tools in alpine.
For that, we'll use [dockerize](https://github.com/larsks/dockerize) to pack the needed ELF binaries that we add to alpine.


#### Usage
```
./build.sh
```

This will create a **dockerized-phantomjs.tgz** file with the necessary ELF binaries in it.
This file is then used when building the alpine version.
67 changes: 67 additions & 0 deletions docker/jenkins/alpine/tools/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#!/bin/bash

set -eo pipefail

[[ -n "${skip}" ]] && exit 0

[[ -t 3 ]] || exec 3>&1
[[ -t 4 ]] || exec 4>&2


RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'

# lets look were are and move to the directory that contains the Dockerfile.phantomjs
DOCKERNAME="Dockerfile.phantomjs"
DOCKERFILE=$(find `pwd` -type f -name ${DOCKERNAME} -print -quit)
DOCKERFILE_PATH=$(dirname ${DOCKERFILE})
FILENAME="dockerized-phantomjs.tgz"

build() {
info "Building phantomjs shared libs"
call docker build --rm -t phantomjslibs --file ${DOCKERNAME} . || die " [fail]"
call docker run --name phantomjslibs -e PHANTOMJS_VERSION=2.1.1 phantomjslibs || die " [fail]"
call docker cp phantomjslibs:/dockerized-phantomjs.tgz ./${FILENAME} || die " [fail]"
call docker rm phantomjslibs || die " [fail]"
info " [done]\n"
}

die() {
echo -e "${RED}$1${NC}" >&4
exit 1
}

info() {
echo -n -e "${GREEN}$1${NC}" >&3
}

call() {
local cmd=$@
[[ -z ${quiet} ]] && info "\n"
if [[ -n "${debug}" ]]; then
echo "${cmd}" >&5
return 0
else
$@ >&4 >&2
fi
}

## is debug enabled?
if [[ -n "${debug}" ]]; then
[[ -t 5 ]] || exec 5>&3
exec 3>/dev/null
fi
if [[ -n "${quiet}" ]]; then
exec 1>/dev/null
exec 2>/dev/null
fi

pushd ${DOCKERFILE_PATH}
# skip if file exists to avoid unnecessary work, but let debug print the commands
if [[ -f ${FILENAME} && -z ${force} ]] && [[ -z "${debug}" ]]; then
info "File \"${FILENAME}\" exists. Skipping build!\n"
else
build
fi
popd
20 changes: 20 additions & 0 deletions docker/jenkins/alpine/tools/pack_libs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/sh


OUTPUT="dockerized-phantomjs"

# This builds an image containing the binaries from the phantomjs.
# curl is included in the build so that internet connections work fine
rm -rf ${OUTPUT}
dockerize -n -o ${OUTPUT} \
--verbose \
$(which phantomjs) \
$(which curl)

rm ${OUTPUT}/Dockerfile
rm ${OUTPUT}/$(which phantomjs)

# taring archive
cd ${OUTPUT} && \
tar -zcf ../dockerized-phantomjs.tgz ./lib ./lib64 ./usr/lib && \
cd ..
7 changes: 6 additions & 1 deletion docker/jenkins/bootstrap/configureGlobalSettings.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@
- CSRF Protection
- Disable CLI remoting
- Markup Formatter
- Project name restrictions
*/
import hudson.markup.RawHtmlMarkupFormatter
import hudson.security.csrf.DefaultCrumbIssuer
import jenkins.CLI
import jenkins.model.Jenkins
import jenkins.model.ProjectNamingStrategy
import jenkins.security.s2m.AdminWhitelistRule
import org.apache.commons.io.FileUtils

Expand Down Expand Up @@ -69,7 +71,7 @@ if (!jenkins.isQuietingDown()) {
/*
Prevent Cross Site Request Forgery exploits
*/
jenkins.setCrumbIssuer(new DefaultCrumbIssuer(true))
jenkins.crumbIssuer = new DefaultCrumbIssuer(true)
logger.info 'Configured CSRF Protection'

/*
Expand All @@ -80,6 +82,9 @@ if (!jenkins.isQuietingDown()) {
logger.info 'Configured Markup Formatter'
}

jenkins.projectNamingStrategy =
new ProjectNamingStrategy.PatternProjectNamingStrategy('[a-z0-9-\\.]{3,50}',"", true)

jenkins.save()

CLI.get().setEnabled(false)
Expand Down
3 changes: 2 additions & 1 deletion docker/jenkins/bootstrap/configureSamplePipelineJob.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import org.jenkinsci.plugins.workflow.job.WorkflowJob


def jenkins = Jenkins.getInstance()
def jobName = 'sample pipeline'
// workdir names with spaces causes problems in javascript builds
def jobName = 'sample-pipeline'
def env = System.getenv()

if (!jenkins.isQuietingDown()) {
Expand Down
119 changes: 97 additions & 22 deletions docker/jenkins/go.sh
Original file line number Diff line number Diff line change
@@ -1,48 +1,123 @@
#!/bin/bash

set -eo pipefail

[[ -t 3 ]] || exec 3>&1 # Open file descriptor 3, writing to wherever stdout currently writes
[[ -t 4 ]] || exec 4>&2 # Open file descriptor 4, writing to wherever stderr currently writes


REPOSITORY=pentaho/jenkins
JENKINS_HOME=/var/jenkins_home
DOCKER_VOLUME=jenkins_pipeline:${JENKINS_HOME}
DOCKER_VOLUME=${VOLUME_NAME:-jenkins_pipeline}:${JENKINS_HOME}
SECRETS=`pwd`/secrets/credentials:/usr/share/jenkins/secrets/credentials

RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'

die() {
echo -e "${RED}$1${NC}" >&4
exit 1
}

info() {
echo -n -e "${GREEN}$1${NC}" >&3
}

call() {
local cmd=$@
if [[ -n "${debug}" ]]; then
echo "${cmd}" >&5
return 0
else
$@ >&4 >&2
fi
}

build() {
[[ -n "${skip}" ]] && return 0
local version=$1
local variant=$2
local tag="${version}${variant}"
#local build_opts=(--no-cache --pull --rm)
local build_opts=(--pull --rm)
#local build_opts=(--no-cache --squash --pull --rm)
local opts=("${build_opts[@]:---pull --rm}")

docker build --file "Dockerfile$variant" \
"${build_opts[@]+"${build_opts[@]}"}" \
--tag "${REPOSITORY}:${tag}" .
build_libs_for_alpine

info "Building Jenkins ${tag}"
call docker build --file "Dockerfile$variant" \
"${opts[@]+"${opts[@]}"}" \
--tag "${REPOSITORY}:${tag}" . && \
info " [done]\n" || die " [fail]"
}

start() {
local version=$1
local variant=$2
local tag="${version}${variant}"
local run_opts=(-it --rm -v ${DOCKER_VOLUME} -v ${SECRETS})
local opts=("${run_opts[@]:--it --rm -v ${DOCKER_VOLUME} -v ${SECRETS}}")

docker run \
"${run_opts[@]+"${run_opts[@]}"}" \
info "Starting Jenkins\n"
call docker run \
"${opts[@]+"${opts[@]}"}" \
-p 8080:8080 \
"${REPOSITORY}:${tag}"
}

variant=""
build_libs_for_alpine() {
[[ -n "${build_libs}" ]] && . alpine/tools/build.sh || return 0
}

printHelp() {
echo "usage: ${PROGNAME} [options]"
echo " options:"
echo -e " -h, --help\t\t\t This help message"
echo -e " -v, --variant string\t Sets the variant of the jenkins container."
echo -e " --debug \t\t Enable debug mode, this will only print the commands that will be run."
echo -e " -q, --quiet \t\t Enable quiet mode."
echo -e " -d, --daemon \t\t Run in daemon mode."
echo -e " -n, --no-build \t\t Skip the building part."
echo -e " -f, --force \t\t Force building from the start."
}

while [[ $# -gt 0 ]]; do
key="$1"
case $key in
-v|--variant)
variant="-"$2
shift
;;
*)
echo "Unknown option: $key"
return 1
;;
esac
shift
opt="$1"
case "$opt" in
-h|--help )
printHelp
exit 0
;;
-v|--variant )
[[ -z $2 || $2 == -* ]] && die "$opt requires an argument"
variant="-"$2
build_libs="ok"
shift
;;
-q|--quiet )
exec 1>/dev/null # Redirect stdout to /dev/null, leaving fd 3 alone
exec 2>/dev/null # Redirect stderr to /dev/null, leaving fd 4 alone
export quiet="ok"
;;
--debug )
[[ -t 5 ]] || exec 5>&3
exec 3>/dev/null
export debug="ok"
;;
-d|--daemon )
run_opts=(-d --rm -v ${DOCKER_VOLUME} -v ${SECRETS})
;;
-n|--no-build )
export skip="ok"
;;
-f|--force )
build_opts=(--no-cache --pull --rm)
export force="ok"
;;
* )
die "Unknown option: $opt"
;;
esac
shift;
done

build "lts" "$variant"
Expand Down

0 comments on commit 3a1a632

Please sign in to comment.