Skip to content
This repository has been archived by the owner on Jan 18, 2020. It is now read-only.

[JENKINS-49866] Automatically configure Docker Cloud if a Docker host is available #95

Merged
merged 14 commits into from
Jun 7, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ RUN apk add --no-cache git \
supervisor \
nodejs \
ttf-dejavu \
curl
curl \
socat

# TODO: add a checksum check?
RUN cd /tmp && \
Expand Down Expand Up @@ -114,3 +115,5 @@ RUN touch ${JENKINS_VAR}/logs/essentials.log.0
# Important: this must be done *after* the chown

VOLUME ${EVERGREEN_HOME}

USER root
30 changes: 23 additions & 7 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,29 @@ pipeline {
}
}

stage('Test jenkins/evergreen') {
steps {
sh 'make container-check'
}
post {
always {
archiveArtifacts artifacts: 'build/tests-run*/**.log*'
stage('Test images') {
parallel {
stage('Base image') {
agent { label 'linux' }
steps {
sh 'make base-container-check'
}
post {
always {
archiveArtifacts artifacts: 'build/tests-run*/**.log*'
}
}
}
stage('Docker Cloud image') {
agent { label 'linux' }
steps {
sh 'make docker-cloud-container-check'
}
post {
always {
archiveArtifacts artifacts: 'build/tests-run*/**.log*'
}
}
}
}
}
Expand Down
15 changes: 13 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,24 @@ fix-formatting:

container-prereqs: build/jenkins-support build/jenkins.sh

container-check: shunit2 ./tests/tests.sh containers
container-check-prereqs: shunit2 ./tests/tests.sh ./tests/offline-tests.sh

container-check: base-container-check docker-cloud-container-check

base-container-check: containers container-check-prereqs
$(MAKE) -C services dump
./tests/offline-tests.sh
./tests/tests.sh

docker-cloud-container-check: containers container-check-prereqs
$(MAKE) -C services dump
ENVIRONMENT=docker-cloud ./tests/offline-tests.sh
ENVIRONMENT=docker-cloud ./tests/tests.sh

container: container-prereqs Dockerfile config/supervisord.conf
$(MAKE) -C client unit
docker build -t ${JENKINS_CONTAINER}:latest .
$(MAKE) -C environments $@

containers: container
$(MAKE) -C services container
Expand Down Expand Up @@ -66,4 +77,4 @@ build/jenkins-support:
shunit2:
git clone --depth 1 https://github.com/kward/shunit2

.PHONY: all check clean container container-check container-prereqs
.PHONY: all check clean container container-check container-prereqs container-check-prereqs base-container-check docker-cloud-container-check
10 changes: 5 additions & 5 deletions client/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ NODE:=../tools/node

all: check

lint:
lint: depends
$(NODE) npm run eslint

fix-formatting:
fix-formatting: depends
$(NODE) npm run eslint -- --fix

check: depends lint
check: lint
$(MAKE) unit

unit:
unit: depends
$(NODE) npm run jest

depends: node_modules
Expand All @@ -23,7 +23,7 @@ node_modules: package-lock.json package.json
$(NODE) npm install; \
fi;

run: run-services
run: depends run-services
EVERGREEN_HOME=/tmp/evergreen-home \
EVERGREEN_ENDPOINT=http://127.0.0.1:3030 \
$(NODE) npm run client
Expand Down
4 changes: 4 additions & 0 deletions config/supervisord.conf
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
redirect_stderr=true
startsecs=2
user=jenkins

[program:jenkins]
command=/usr/local/bin/jenkins.sh
Expand All @@ -23,3 +24,6 @@ stdout_logfile_maxbytes=0
redirect_stderr=true
startsecs=10
startretries=0
user=jenkins

# vim: ft=ini
5 changes: 5 additions & 0 deletions environments/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
JENKINS_CONTAINER:=jenkins/evergreen
DOCKERCLOUD_TAGNAME:=docker-cloud

container: docker-cloud/Dockerfile
cd docker-cloud && docker build -t ${JENKINS_CONTAINER}:${DOCKERCLOUD_TAGNAME} .
4 changes: 4 additions & 0 deletions environments/docker-cloud/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM jenkins/evergreen

COPY config/as-code/* /usr/share/jenkins/ref/configuration/
COPY config/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
17 changes: 17 additions & 0 deletions environments/docker-cloud/config/as-code/docker-cloud.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
jenkins:
clouds:
- docker:
name: "docker"
dockerApi:
dockerHost:
uri: "tcp://localhost:2375/"
templates:
- labelString: "agent"
dockerTemplateBase:
image: "jenkins/slave"
remoteFs: "/home/jenkins/agent"
connector:
attach:
user: "jenkins"
instanceCapStr: "10"
48 changes: 48 additions & 0 deletions environments/docker-cloud/config/supervisord.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
[supervisord]
nodaemon=true

[inet_http_server]
port=:9001

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

[program:evergreen-client]
command=/usr/bin/npm run client
directory=%(ENV_EVERGREEN_HOME)s/client
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
redirect_stderr=true
startsecs=2
user=jenkins

[program:jenkins]
command=/usr/local/bin/jenkins.sh
directory=%(ENV_JENKINS_HOME)s
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
redirect_stderr=true
startsecs=10
startretries=0
user=jenkins

# The configuration and usage of socat below requires an explanation.
# The intent is to provide an out-of-the-box Essentials instance able to run builds using Docker.
# The chosen path for this is to require that the Docker socket be bind-mounted.
#
# As the Jenkins instance user is *not* root, it can not use /var/run/docker.sock by default
# in a typical setup. Because when mounted with `-v /var/run/docker.sock:/var/run/docker.sock` the
# socket will not be writable to the world, and depending on the setup not even readable.
#
# So, there are two paths forward:
# * Either we require that the administrators on the host run `chmod a+rw /var/run/docker.sock`, or
# * we just expose that file as a full TCP socket, listening on the usual 2375 port.
#
# We chose the latter because it seemed less work for the Essentials users, and hence more in line
# with the overall easiness Jenkins Essentials aims at providing.
[program:socat]
command=socat -d -d TCP4-LISTEN:2375,fork UNIX-CONNECT:/var/run/docker.sock
startsecs=0
stdout_logfile=/dev/stdout

# vim: ft=ini
63 changes: 63 additions & 0 deletions services/src/services/update/update.hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ class UpdateHooks {
'signature' : 'abc97028893c8a71581a5f559ea48e8e1f1a65164faee96dabfed9e95e9abad2'
}
},
{
'url' : 'https://updates.jenkins.io/latest/authentication-tokens.hpi',
'checksum' : {
'type' : 'sha256',
'signature' : 'abc97028893c8a71581a5f559ea48e8e1f1a65164faee96dabfed9e95e9abad2'
}
},
{
'url' : 'https://updates.jenkins.io/latest/bouncycastle-api.hpi',
'checksum' : {
Expand Down Expand Up @@ -150,6 +157,41 @@ class UpdateHooks {
'signature' : 'c4f964c6deb599816f6740ef674cb6dd2644d5f1b4e7b886a948f778ec5c189e'
}
},
{
'url' : 'https://updates.jenkins.io/latest/credentials-binding.hpi',
'checksum' : {
'type' : 'sha256',
'signature' : 'c4f964c6deb599816f6740ef674cb6dd2644d5f1b4e7b886a948f778ec5c189e'
}
},
{
'url' : 'https://updates.jenkins.io/latest/docker-java-api.hpi',
'checksum' : {
'type' : 'sha256',
'signature' : '94a367b3810cb3175c78490616d0d5f7fb4f7f710c24583901da5159f3d93e0c'
}
},
{
'url' : 'https://repo.jenkins-ci.org/incrementals/io/jenkins/docker/docker-plugin/1.1.5-rc591.93ebeb1fd9ab/docker-plugin-1.1.5-rc591.93ebeb1fd9ab.hpi',
'checksum' : {
'type' : 'sha256',
'signature' : '94a367b3810cb3175c78490616d0d5f7fb4f7f710c24583901da5159f3d93e0c'
}
},
{
'url' : 'https://updates.jenkins.io/latest/docker-commons.hpi',
'checksum' : {
'type' : 'sha256',
'signature' : '94a367b3810cb3175c78490616d0d5f7fb4f7f710c24583901da5159f3d93e0c'
}
},
{
'url' : 'https://updates.jenkins.io/latest/durable-task.hpi',
'checksum' : {
'type' : 'sha256',
'signature' : '94a367b3810cb3175c78490616d0d5f7fb4f7f710c24583901da5159f3d93e0c'
}
},
{
'url' : 'https://updates.jenkins.io/latest/essentials.hpi',
'checksum' : {
Expand Down Expand Up @@ -206,6 +248,13 @@ class UpdateHooks {
'signature' : 'e7c11c9a751809258f0016221a99f6dc820bd6513600e913e3847551db53d34f'
}
},
{
'url' : 'https://updates.jenkins.io/latest/plain-credentials.hpi',
'checksum' : {
'type' : 'sha256',
'signature' : 'e7c11c9a751809258f0016221a99f6dc820bd6513600e913e3847551db53d34f'
}
},
{
'url' : 'https://updates.jenkins.io/latest/scm-api.hpi',
'checksum' : {
Expand All @@ -227,13 +276,27 @@ class UpdateHooks {
'signature' : '837a2ed38069d8bc089c5370eaa5858edc519433801949fd6b84d05444f13afe'
}
},
{
'url' : 'https://updates.jenkins.io/latest/ssh-slaves.hpi',
'checksum' : {
'type' : 'sha256',
'signature' : '837a2ed38069d8bc089c5370eaa5858edc519433801949fd6b84d05444f13afe'
}
},
{
'url' : 'https://updates.jenkins.io/latest/structs.hpi',
'checksum' : {
'type' : 'sha256',
'signature' : '43a27488fd58f95affdef0766570bbe705ac8c39fe11d3b38208282c21cac58b'
}
},
{
'url' : 'https://updates.jenkins.io/latest/token-macro.hpi',
'checksum' : {
'type' : 'sha256',
'signature' : '43a27488fd58f95affdef0766570bbe705ac8c39fe11d3b38208282c21cac58b'
}
},
{
'url' : 'https://updates.jenkins.io/latest/workflow-api.hpi',
'checksum' : {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
version: '3'
services:

instance:
image: jenkins/evergreen:docker-cloud
volumes:
- /var/run/docker.sock:/var/run/docker.sock
18 changes: 9 additions & 9 deletions tests/offline-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,22 +23,22 @@ test_docker_CLI_available() {

# Check that not only something called docker can be found on the PATH
# but is actually looking more like it using a specific command call
output=$( docker exec "$container_under_test" docker version 2>&1 )
assertEquals "error is expected since no Docker daemon $?" 1 $?

echo "$output" | \
grep "Cannot connect to the Docker daemon" > /dev/null
assertEquals "expected message about daemon unavailable" 0 $?
output=$( docker exec "$container_under_test" docker --version 2>&1 | cut -d ' ' -f 1,2 )
assertEquals "Command should succeed" 0 "$?"
assertEquals "Should start with 'Docker version ...'" "Docker version" "$output"
}

# JENKINS-50195
test_not_root() {
username=$( docker exec "$container_under_test" whoami )
assertEquals "jenkins" "$username"
assertEquals "root" "$username"

for process_user in $( docker exec "$container_under_test" ps -o user | grep -v USER)
docker exec "$container_under_test" ps -o user= -o comm= | \
grep -E 'jenkins|npm' | \
while read process_user
do
assertEquals "jenkins" "$process_user"
currentUser=$( echo "$process_user" | awk '{print $1}' )
assertEquals "User for '$process_user' should be jenkins" "jenkins" "$currentUser"
done
}

Expand Down
31 changes: 15 additions & 16 deletions tests/tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,6 @@ test_no_node_error_in_logs() {
endSkipping
}

# JENKINS-49864
test_docker_CLI_available() {
docker exec "$container_under_test" which docker > /dev/null
assertEquals "docker found in the PATH" 0 $?

# Check that not only something called docker can be found on the PATH
# but is actually looking more like it using a specific command call
output=$( docker exec "$container_under_test" docker version 2>&1 )
assertEquals "error is expected since no Docker daemon $?" 1 $?

echo "$output" | \
grep "Cannot connect to the Docker daemon" > /dev/null
assertEquals "expected message about daemon unavailable" 0 $?
}

# JENKINS-49861
test_no_executor() {
numExecutors=$( docker exec "$container_under_test" cat "$JENKINS_HOME/config.xml" | \
Expand Down Expand Up @@ -152,7 +137,7 @@ test_logs_are_propagated() {

# Test everything under /evergreen is owned by the jenkins user
test_evergreen_home_is_fully_owned_by_jenkins_user() {
result=$( docker exec "$container_under_test" find . \! -user jenkins -print )
result=$( docker exec "$container_under_test" find . \! -user jenkins \! -name "supervisor*" -print )
assertEquals "Some files are not owned by 'jenkins', should not happen!" "" "$result"
}

Expand All @@ -167,4 +152,18 @@ test_error_telemetry_service_is_secured() {

}

# JENKINS-49866
test_docker_available_as_jenkins_user() {

[[ "$ENVIRONMENT" = "docker-cloud" ]] || startSkipping

$COMPOSE exec -T instance bash -c 'su - jenkins -c "DOCKER_HOST=localhost:2375 /usr/local/bin/docker version"' > /dev/null
assertEquals "command should succeed" 0 "$?"

$COMPOSE exec -T instance bash -c 'su - jenkins -c "DOCKER_HOST=localhost:2375 /usr/local/bin/docker run hello-world"' > /dev/null
assertEquals "docker run hello-world" 0 "$?"

[[ "$ENVIRONMENT" = "docker-cloud" ]] || endSkipping
}

. ./shunit2/shunit2
Loading