testing: add offline testing container for CI

This patch adds the necessary code for building a container that can be
used for our CI functional and fullstack testing needs. The only
requirement for building is a working docker engine and the OS to have
access to a packaging mirror (which CI is supposed to have even when
internet connectivity is limited).

In order to build, simply move to 'contrib/testing/container' and run:

    ./build.sh

To try it out locally, just do:

    docker build -t kuryr/testing_container .
    docker run --rm -p 8000:8000 kuryr/testing_container

And from another terminal:

    curl 0:8000

Change-Id: Id94ad2d7567f9e5d60fce25d29c8c3d4a391aabc
Signed-off-by: Antoni Segura Puimedon <antonisp@celebdor.com>
This commit is contained in:
Antoni Segura Puimedon 2017-01-03 02:46:46 +01:00
parent 998c82aebd
commit b267a108e3
No known key found for this signature in database
GPG Key ID: B71BE48A9A349926
3 changed files with 175 additions and 0 deletions

View File

@ -0,0 +1,3 @@
FROM scratch
ADD kuryr_testing_rootfs.tar.gz /
CMD ["/usr/bin/kuryr_hostname"]

View File

@ -0,0 +1,43 @@
#!/bin/bash
set -o errexit
function install_busybox {
if [[ -x $(command -v apt-get 2> /dev/null) ]]; then
sudo apt-get update
sudo apt-get install -y busybox-static gcc
elif [[ -x $(command -v dnf 2> /dev/null) ]]; then
sudo dnf install -y busybox gcc
elif [[ -x $(command -v yum 2> /dev/null) ]]; then
sudo yum install -y busybox gcc
elif [[ -x $(command -v pacman 2> /dev/null) ]]; then
sudo pacman -S --noconfirm busybox gcc
else
echo "unknown distro" 1>2
exit 1
fi
return 0
}
function make_root {
local root_dir
local binary
root_dir=$(mktemp -d)
mkdir -p "${root_dir}/bin" "${root_dir}/usr/bin"
binary=$(command -v busybox)
cp "$binary" "${root_dir}/bin/busybox"
"${root_dir}/bin/busybox" --install "${root_dir}/bin"
gcc --static hostname.c -o "${root_dir}/usr/bin/kuryr_hostname"
tar -C "$root_dir" -czvf kuryr_testing_rootfs.tar.gz bin usr
return 0
}
function build_container {
docker build -t kuryr/test_container .
}
install_busybox
make_root
build_container

View File

@ -0,0 +1,129 @@
#define _GNU_SOURCE
#include <arpa/inet.h>
#include <err.h>
#include <errno.h>
#include <linux/in.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#define MAX_LEN 1024
#define BACKLOG 10
#define LISTENING_PORT 8000
volatile sig_atomic_t running = 1;
volatile sig_atomic_t sig_number;
static void handler(int signo) {
sig_number = signo;
running = 0;
}
int main() {
struct sigaction sa = {
.sa_handler = handler,
.sa_flags = 0};
sigemptyset(&sa.sa_mask);
if (sigaction(SIGINT, &sa, NULL) == -1) {
err(1, "Failed to set SIGINT handler");
}
if (sigaction(SIGTERM, &sa, NULL) == -1) {
err(1, "Failed to set SIGTERM handler");
}
int enable = 1;
int result = 1;
char hostname[MAX_LEN];
int res = gethostname(hostname, MAX_LEN);
if (res < 0) {
err(1, "Failed to retrieve hostname");
}
char *response;
ssize_t responselen;
responselen = asprintf(&response, "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"%s\r\n", hostname);
if (responselen == -1) {
err(1, "Failed to form response");
}
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("Failed to open socket");
goto nosocket;
}
res = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable,
sizeof(int));
if (res < 0) {
perror("Failed to set socket options");
goto cleanup;
}
struct sockaddr_in srv = {
.sin_family = AF_INET,
.sin_port = htons(LISTENING_PORT),
.sin_addr = { .s_addr = INADDR_ANY}};
socklen_t addrlen= sizeof(srv);
res = bind(sock, (struct sockaddr *) &srv, (socklen_t) sizeof(srv));
if (res < 0) {
res = close(sock);
if (res == -1) {
perror("Failed close socket");
goto cleanup;
}
perror("Failed to bind socket");
goto cleanup;
}
res = listen(sock, BACKLOG);
if (res < 0) {
perror("Failed to set socket to listen");
goto cleanup;
}
while (running) {
struct sockaddr_in cli;
int client_fd = accept(sock, (struct sockaddr *) &cli,
&addrlen);
if (client_fd == -1) {
if (running) {
perror("failed to accept connection");
continue;
} else {
char *signame = strsignal(sig_number);
printf("Received %s. Quitting\n", signame);
break;
}
}
fprintf(stderr, "Accepted client connection\n");
/* Assume we write it all at once */
write(client_fd, response, responselen);
res = shutdown(client_fd, SHUT_RDWR);
if (res == -1) {
perror("Failed to shutdown client connection");
goto cleanup;
}
res = close(client_fd);
if (res == -1) {
perror("Failed to close client connection");
goto cleanup;
}
}
result = 0;
cleanup:
close(sock);
nosocket:
free(response);
return result;
}