“Besides black art, there is only automation and mechanization.” Federico García Lorca
Where I work, Jenkins is what we use for continuous integration. Skype is what we use to communicate. Now imagine with me that every day, at least 6 times, I’m being asked to run a build, and then another 6 to check the status of the build! And then another 6 times to run a deploy.
And guess what? Another 6 times to check the status of the deploy, which is then followed by 4 questions on why the platform is down!
All this because some managers are too scared to let non-technical people touch Jenkins, and some of the non-technical people are too lazy to take the initiative to know how to run or check Jenkins’ jobs.
I was getting annoyed and bored with these repetitive tasks, so I decided to build a robot and delegate these jobs to it.
Every request is sent directly to the robot as a command. It performs the action automatically, and listens for any change on the status of the Jenkins job. If it detects any change or transition, it sends us a notification.
The robot is just Python script running on the background as demon, using Skype4Py and Jenkins API module, and some basic logic that can be easily extended.
Things are not so easy as they look however, and so I will present a step by step guide to how I built a functional Robot.
First, we cannot run two instances of Skype on the same machine, and I could not use another Windows machine. I had access to the server where Jenkins is installed: so why not install Skype there and run the python script?
The Server has no GUI! That was not an issue. I had only to forward X11 socket to my machine. The problem was that there is no installable version of Skype on that server.
Docker is what I thought of to solve the problem – so it was time for free shopping from Docker Hub!
FROM python:2.7.10 MAINTAINER Youssef El Jaoujat <email@example.com> # Tell debconf to run in non-interactive mode ENV DEBIAN_FRONTEND noninteractive RUN apt-get -f install --fix-missing # Setup multiarch because Skype is 32bit only # Make sure the repository information is up to date RUN dpkg --add-architecture i386 && apt-get update && apt-get install -y curl --no-install-recommends # Install Skype RUN curl http://download.skype.com/linux/skype-debian_184.108.40.206-1_i386.deb -o /usr/src/skype.deb RUN dpkg -i /usr/src/skype.deb || true # Automatically detect and install dependencies RUN apt-get -fy install --fix-missing RUN rm -rf /var/lib/apt/lists/* # pureg temp data # Start Skype ENTRYPOINT ["skype"]
To build this, Docker just executes from the command line:
docker build -t eljoujat/skype .
At this point, I have a Docker container with Skype and Python installed inside. To test the container, just run the container:
docker run -it -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=unix$DISPLAY --device /dev/snd eljoujat/skype
If you get an error with the x11 protocols , just run the following command to grant access to everyone:
Our Python uses two modules that need to be installed. We have just to add the instruction on the Docker file and rebuild the image.
## Install Python modules RUN apt-get install -y python-pip && pip install Skype4Py && pip install jenkinsapi
Next step is to make the script available inside the image so we can execute.
A best practice when working with Docker is decoupling applications into multiple containers. For the sake of simplicity, I did not completely respect this rule, but it’s simple to apply with the script and make things very easy.
So, to do it I had just to use ‘-v’ option when running the Docker image
docker run -it -v /tmp/.X11-unix:/tmp/.X11-unix -v /media/eljaoujat/Linux/job/labs/docker/skype:/scripts/scripts -e DISPLAY=unix$DISPLAY --device /dev/snd eljoujat/skype:V1.1
/media/eljaoujat/Linux/job/labs/docker/skype is my locale folder and/scripts/scripts will be created inside the container and will be mapped with my locale folder
When running the image, Skype gets executed…oops !
I have no problem with the term of use (or I have !?) and login, but doing it each time I run the container is not good at all.
I searched for a solution to automate this on the Docker file but with no help, there is no argument we can pass to Skype so it will connect automatically.
The only solution I found is to use the commit command of Docker.
This command allows you to make the change directly on the running container and create a new image from this changes. It was so easy and simple, I had just to accept the terms and login with the remember me option .
docker commit b2ec5c9e295e eljoujat/skype:v.1.1
b2ec5c9e295e is the container ID can be obtained by running:
after that I fall in love with Docker instantly.
Let’s check what happens inside the Container, and test our script . To do this we have to access via SSH, which has to be added to the Docker file and the image has to be rebuilt.
A better solution is to use nsenter to install run the following command:
docker run --rm -v /usr/local/bin:/target jpetazzo/nsenter
To use nsenter with a running container we should first get this ID:
Get the PID:
PID=$(docker inspect --format 1d46c2cb556c)
Then use nsenter:
sudo nsenter --target $PID --mount --uts --ipc --net --pid
After lsing the /scrtips directory inside the container we find our Python script.
We can also run it and see what works well.
At this point, all that is left to do is to run the script automatically when the container starts.
A good solution I found for this is to use supervisor. Supervisor is a process control system, and when it’s added to the container it will allow us to execute as many processes as we want – we have just to configure them. In our case, we want to execute our Python script once the container starts. A possible configuration file could be :
[supervisord] nodaemon=false [include] files = /etc/supervisor/conf.d/*.conf [program:skype] command=python /scripts/buildchatbot.py autostart=true autorestart=true startretries=20 stderr_logfile=/opt/nodehook.err.log stdout_logfile=/opt/nodehook.out.log
So I added supervisor and rebuilt the image with a higher tag version.
The final dockerfile version is :
FROM python:2.7.10 MAINTAINER Youssef El Jaoujat <firstname.lastname@example.org> # Tell debconf to run in non-interactive mode ENV DEBIAN_FRONTEND noninteractive RUN apt-get -f install --fix-missing # Setup multiarch because Skype is 32bit only # Make sure the repository information is up to date RUN dpkg --add-architecture i386 && apt-get update && apt-get install -y curl --no-install-recommends # Install Skype RUN curl http://download.skype.com/linux/skype-debian_220.127.116.11-1_i386.deb -o /usr/src/skype.deb RUN dpkg -i /usr/src/skype.deb || true RUN apt-get -fy install --fix-missing # Automatically detect and install dependencies RUN rm -rf /var/lib/apt/lists/* # pureg temp data # Install Supervisor RUN sed -i 's/# (.*multiverse$)/1/g' /etc/apt/sources.list && apt-get update && apt-get -y upgrade # supervisor installation && # create directory for child images to store configuration in RUN apt-get -y install supervisor && mkdir -p /var/log/supervisor && mkdir -p /etc/supervisor/conf.d # supervisor base configuration ## Install skype4py and jenkinsapi modules RUN apt-get install -y python-pip && pip install Skype4Py && pip install jenkinsapi # add the Supervisor config ADD supervisor.conf /etc/supervisor.conf CMD [ "sh", "-c", " supervisord -c /etc/supervisor.conf && skype" ]
docker build -t eljoujat/skype:V1.2 .
docker run -it -v /tmp/.X11-unix:/tmp/.X11-unix -v /media/eljaoujat/Linux/job/labs/docker/skype:/scripts/scripts -e DISPLAY=unix$DISPLAY --device /dev/snd eljoujat/skype:V1.2
-To test: just send a messgae to the Jenkins robot telling it to run a job.
“I believe that there is always an other way to do it, and i hope that you let me know .”