From b267a108e3ae73ca93b159868fef4c3cf7262894 Mon Sep 17 00:00:00 2001 From: Antoni Segura Puimedon Date: Tue, 3 Jan 2017 02:46:46 +0100 Subject: [PATCH] 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 --- contrib/testing/container/Dockerfile | 3 + contrib/testing/container/build.sh | 43 +++++++++ contrib/testing/container/hostname.c | 129 +++++++++++++++++++++++++++ 3 files changed, 175 insertions(+) create mode 100644 contrib/testing/container/Dockerfile create mode 100755 contrib/testing/container/build.sh create mode 100644 contrib/testing/container/hostname.c diff --git a/contrib/testing/container/Dockerfile b/contrib/testing/container/Dockerfile new file mode 100644 index 000000000..13f0ff698 --- /dev/null +++ b/contrib/testing/container/Dockerfile @@ -0,0 +1,3 @@ +FROM scratch +ADD kuryr_testing_rootfs.tar.gz / +CMD ["/usr/bin/kuryr_hostname"] diff --git a/contrib/testing/container/build.sh b/contrib/testing/container/build.sh new file mode 100755 index 000000000..804c51fa3 --- /dev/null +++ b/contrib/testing/container/build.sh @@ -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 diff --git a/contrib/testing/container/hostname.c b/contrib/testing/container/hostname.c new file mode 100644 index 000000000..e31778261 --- /dev/null +++ b/contrib/testing/container/hostname.c @@ -0,0 +1,129 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +}