Badges from REST services through mod_proxy
I see many projects on GitHub, which use badges to show information about build status, code coverage and so forth.
I really like the idea, because it gives a quick overview of the current state. If all badges are green, the project is probably fine. If not the corresponding issues should be addressed.
In a local environment many tools provide information through a REST API. For example Jenkins, SonarQube or Atlassian JIRA. There are some badge plug-ins available for Jenkins build status or SonarQube quality gate. Since I am interested in more information (e.g. code coverage) I decided to get these information directly from their REST API and convert them into a badge.
Get information from REST services
Unfortunately it is not possible to access the services directly from within the browser (XMLHttpRequest with jQuery), because of the same-origin policy.
var url = 'http://sonar.example.com:9000/api/resources?resource=prj&metrics=coverage';
$.getJSON(url, function (response) {
// will not work
}
The easiest way I could think of to avoid this was the usage of a reverse proxy, which adds the Access-Control-Allow-Origin header (CORS). This is a sample config for two services.
FROM ubuntu
MAINTAINER simdevmon
ENV PORT_JIRA 8080
ENV URL_JIRA http://jira.example.com:8080/
ENV PORT_SONAR 9000
ENV URL_SONAR http://sonar.example.com:9000/
ENV PORT_CONFIG /etc/apache2/ports.conf
ENV SITE_CONFIG /etc/apache2/sites-enabled/000-default.conf
RUN \
apt-get update && \
apt-get install -y \
apache2 \
libapache2-mod-proxy-html \
libxml2-dev
RUN \
a2enmod proxy proxy_http && \
a2enmod headers && \
service apache2 restart && \
service apache2 stop
RUN \
echo '<VirtualHost *:'${PORT_JIRA}'>' > "${SITE_CONFIG}" && \
echo ' Header set Access-Control-Allow-Origin "*"' >> "${SITE_CONFIG}" && \
echo ' ProxyPass / '${URL_JIRA} >> "${SITE_CONFIG}" && \
echo ' ProxyPassReverse / '${URL_JIRA} >> "${SITE_CONFIG}" && \
echo '</VirtualHost>' >> "${SITE_CONFIG}" && \
echo '<VirtualHost *:'${PORT_SONAR}'>' >> "${SITE_CONFIG}" && \
echo ' Header set Access-Control-Allow-Origin "*"' >> "${SITE_CONFIG}" && \
echo ' ProxyPass / '${URL_SONAR} >> "${SITE_CONFIG}" && \
echo ' ProxyPassReverse / '${URL_SONAR} >> "${SITE_CONFIG}" && \
echo '</VirtualHost>' >> "${SITE_CONFIG}"
RUN \
echo 'Listen '${PORT_JIRA} > "${PORT_CONFIG}" && \
echo 'Listen '${PORT_SONAR} >> "${PORT_CONFIG}"
RUN \
cat ${SITE_CONFIG} && \
cat ${PORT_CONFIG} && \
apachectl configtest
CMD /bin/bash -c "service apache2 start; tail -f /dev/null"
The docker image can be build and executed like this.
docker build -t badge_proxy .
docker run -p 8080:8080 -p 9000:9000 badge_proxy
Now it is possible to use XMLHttpRequests from within the browser to all required services.
Convert information into badges
Shields.io provides a great way to generate badges. They also provide a docker image, which is described in the installation guide.
In this example I will just use the online service to generate the badge.
<script type="text/javascript">
function coverageColor(coverage) {
var color = 'brightgreen';
if (coverage < 90) {
color = 'yellow';
}
if (coverage < 70) {
color = 'red';
}
return color;
}
var url = 'http://sonar.example.com:9000/api/resources?resource=prj&metrics=coverage';
var baseImage = 'https://img.shields.io/badge/';
$.getJSON(url, function (response) {
var coverage;
var metrics = response[0].msr;
for (var i = 0; i < metrics.length; i++) {
if (metrics[i].key === 'coverage') {
coverage = metrics[i].val;
}
}
document.getElementById('coverage').src = baseImage +
'coverage-' + coverage + ' %-' + coverageColor(coverage) + '.svg';
}).error(function (jqXHR, textStatus, errorThrown) {
document.getElementById('coverage').src = baseImage +
'coverage-N%20/%20A-red.svg';
});
</script>
<a href="http://sonar.example.com:9000">
<img id="coverage" src="#" alt=""/>
</a>
To see if a service is reachable is even easier.
<script type="text/javascript">
function isServiceUp(url, name, imgId) {
var baseImage = 'https://img.shields.io/badge/' + name;
$.ajaxSetup({cache: false});
$.ajax({
url: url,
method: "GET",
success: function (data, status, jqxhr) {
document.getElementById(imgId).src = baseImage + '-up-brightgreen.svg';
},
error: function (jqxhr, status, error) {
document.getElementById(imgId).src = baseImage + '-down-red.svg';
}
});
}
isServiceUp('http://sonar.example.com:9000/api/system/status', 'sonarqube', 'sonarup');
</script>
<a href="http://sonar.example.com:9000">
<img id="sonarup" src="#" alt=""/>
</a>