From 07be30325ef15247a2a0e11761ba63a29c140857 Mon Sep 17 00:00:00 2001 From: f4exb Date: Mon, 22 Jun 2020 00:04:08 +0200 Subject: [PATCH] REST API Swagger code generation using Docker --- swagger/docker/codegen/Dockerfile | 53 +++++++++++++++++++++++++ swagger/docker/codegen/build.sh | 52 +++++++++++++++++++++++++ swagger/docker/codegen/swagger-codegen | 2 + swagger/docker/compose/compose.yml | 29 ++++++++++++++ swagger/docker/compose/login.sh | 2 + swagger/docker/compose/run.sh | 54 ++++++++++++++++++++++++++ swagger/docker/readme.md | 40 +++++++++++++++++++ swagger/docker/server/Dockerfile | 21 ++++++++++ swagger/docker/server/build.sh | 43 ++++++++++++++++++++ swagger/docker/server/run.sh | 51 ++++++++++++++++++++++++ 10 files changed, 347 insertions(+) create mode 100644 swagger/docker/codegen/Dockerfile create mode 100755 swagger/docker/codegen/build.sh create mode 100755 swagger/docker/codegen/swagger-codegen create mode 100644 swagger/docker/compose/compose.yml create mode 100755 swagger/docker/compose/login.sh create mode 100755 swagger/docker/compose/run.sh create mode 100644 swagger/docker/readme.md create mode 100644 swagger/docker/server/Dockerfile create mode 100755 swagger/docker/server/build.sh create mode 100755 swagger/docker/server/run.sh diff --git a/swagger/docker/codegen/Dockerfile b/swagger/docker/codegen/Dockerfile new file mode 100644 index 000000000..b7c3f3f5f --- /dev/null +++ b/swagger/docker/codegen/Dockerfile @@ -0,0 +1,53 @@ +FROM ubuntu:20.04 AS base +ARG uid + +ENV DEBIAN_FRONTEND=noninteractive + +# Create a user with sudo rights +RUN apt-get update && apt-get -y install sudo +RUN useradd -m appuser -u ${uid} && echo "appuser:appuser" | chpasswd \ + && adduser appuser sudo \ + && sudo usermod --shell /bin/bash appuser +RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers +USER appuser + +# Configure tzdata manually before anything else +ENV TZONE=Europe/Paris +RUN sudo ln -fs /usr/share/zoneinfo/$TZONE /etc/localtime \ + && sudo apt-get update && sudo apt-get -y install tzdata + +# Base packages required +RUN sudo apt-get update && sudo apt-get -y install \ + git \ + vim \ + wget \ + maven \ + openjdk-8-jdk + +# Prepare buiid and install environment +RUN sudo mkdir /opt/build /opt/install \ + && sudo chown appuser:appuser /opt/build /opt/install + +# swagger-codegen +FROM base as codegen_clone +ARG clone_label +WORKDIR /opt/build +RUN git clone --depth 1 https://github.com/f4exb/swagger-codegen.git -b sdrangel \ + && cd swagger-codegen \ + && mkdir build \ + && echo "${clone_label}" > build/clone_label.txt + +FROM base as codegen_build +COPY --from=codegen_clone --chown=appuser /opt/build/swagger-codegen /opt/build/swagger-codegen +WORKDIR /opt/build/swagger-codegen +RUN export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64 \ + && mvn clean package +RUN mkdir -p /opt/install/swagger \ + && cp ./modules/swagger-codegen-cli/target/swagger-codegen-cli.jar /opt/install/swagger + +FROM base as codegen +RUN mkdir -p /opt/build/sdrangel/swagger/sdrangel +COPY --from=codegen_build --chown=appuser /opt/install/swagger /opt/install/swagger +COPY swagger-codegen /opt/install/swagger + +WORKDIR /opt/build/sdrangel/swagger/sdrangel diff --git a/swagger/docker/codegen/build.sh b/swagger/docker/codegen/build.sh new file mode 100755 index 000000000..b1ac9a164 --- /dev/null +++ b/swagger/docker/codegen/build.sh @@ -0,0 +1,52 @@ +#!/bin/sh + +OPTIND=1 # Reset in case getopts has been used previously in the shell. + +# Get options: +show_help() { + cat << EOF + Usage: ${0##*/} [-b branch] [-c label] [-t tag] [-h] + Build SDRangel image. + -b name Branch name (default sdrangel) + -c label Arbitrary clone label. Clone again if different from the last label (default current timestamp) + -t tag Docker image tag. Use git tag or commit hash (default latest) + -f file Specify a Dockerfile (default is Dockerfile in current directory i.e. '.') + -h Print this help. +EOF +} + +branch_name="sdrangel" +clone_label=$(date) +image_tag="latest" +uid=$(id -u) +docker_file="." + +while getopts "h?b:c:t:j:f:" opt; do + case "$opt" in + h|\?) + show_help + exit 0 + ;; + b) branch_name=${OPTARG} + ;; + c) clone_label=${OPTARG} + ;; + t) image_tag=${OPTARG} + ;; + f) docker_file="-f ${OPTARG} ." + ;; + esac +done + +shift $((OPTIND-1)) + +[ "${1:-}" = "--" ] && shift +# End of get options + +IMAGE_NAME=sdrangel/swagger/codegen:${image_tag} +DOCKER_BUILDKIT=1 docker build \ + --build-arg branch=${branch_name} \ + --build-arg clone_label="${clone_label}" \ + --build-arg uid=${uid} \ + --target codegen \ + -t ${IMAGE_NAME} ${docker_file} diff --git a/swagger/docker/codegen/swagger-codegen b/swagger/docker/codegen/swagger-codegen new file mode 100755 index 000000000..acae9ed1a --- /dev/null +++ b/swagger/docker/codegen/swagger-codegen @@ -0,0 +1,2 @@ +#!/bin/sh +/usr/lib/jvm/java-8-openjdk-amd64/bin/java -jar /opt/install/swagger/swagger-codegen-cli.jar ${*} diff --git a/swagger/docker/compose/compose.yml b/swagger/docker/compose/compose.yml new file mode 100644 index 000000000..ec8ad4505 --- /dev/null +++ b/swagger/docker/compose/compose.yml @@ -0,0 +1,29 @@ +version: '3' +services: + swgcodegen: + image: "sdrangel/swagger/codegen:${IMAGE_CODEGEN_VERSION}" + container_name: "sdrangel_swgcodegen" + volumes: + - "${SDRANGEL_BASE}:/opt/build/sdrangel:rw" + networks: + default: + ipv4_address: 172.20.0.2 + stdin_open: true + tty: true + swgserver: + image: "sdrangel/swagger/server:${IMAGE_SERVER_VERSION}" + container_name: "sdrangel_swgserver" + volumes: + - "${SDRANGEL_BASE}:/opt/build/sdrangel:rw" + expose: + - "8081" + networks: + default: + ipv4_address: 172.20.0.3 +networks: + default: + driver: bridge + ipam: + driver: default + config: + - subnet: 172.20.0.0/16 diff --git a/swagger/docker/compose/login.sh b/swagger/docker/compose/login.sh new file mode 100755 index 000000000..4d2a973ee --- /dev/null +++ b/swagger/docker/compose/login.sh @@ -0,0 +1,2 @@ +#!/bin/bash +docker exec -it sdrangel_swgcodegen /bin/bash \ No newline at end of file diff --git a/swagger/docker/compose/run.sh b/swagger/docker/compose/run.sh new file mode 100755 index 000000000..9e6429aa3 --- /dev/null +++ b/swagger/docker/compose/run.sh @@ -0,0 +1,54 @@ +#!/bin/sh + +OPTIND=1 # Reset in case getopts has been used previously in the shell. + +# Get options: +show_help() { + cat << EOF + Usage: ${0##*/} [-t tag] [-T tag] [-D] [-h] + Run http-server and codegen in a Docker compose stack. + -D use this option to bring down the compose stack (default is to bring up). + -t tag Docker codegen image tag (default latest) + -T tag Docker server image tag (default latest) + -b path SDRangel source code root path (default /opt/build/sdrangel) + -c name Compose stack name (default sdrangelswg) + -h Print this help. +EOF +} + +image_tag_codegen="latest" +image_tag_server="latest" +sdrangel_codebase="/opt/build/sdrangel" +stack_name="-p sdrangelswg" +action="up -d" + +while getopts "h?Dt:T:b:c:" opt; do + case "$opt" in + h|\?) + show_help + exit 0 + ;; + D) action="down" + ;; + t) image_tag_codegen=${OPTARG} + ;; + T) image_tag_server=${OPTARG} + ;; + b) sdrangel_codebase=${OPTARG} + ;; + c) stack_name="-p ${OPTARG}" + ;; + esac +done + +shift $((OPTIND-1)) + +[ "${1:-}" = "--" ] && shift +# End of get options + +export USER_UID=$(id -u) +export IMAGE_CODEGEN_VERSION=${image_tag_codegen} +export IMAGE_SERVER_VERSION=${image_tag_server} +export SDRANGEL_BASE=${sdrangel_codebase} + +docker-compose -f compose.yml ${stack_name} ${action} diff --git a/swagger/docker/readme.md b/swagger/docker/readme.md new file mode 100644 index 000000000..4dbd2da6a --- /dev/null +++ b/swagger/docker/readme.md @@ -0,0 +1,40 @@ +

Running Swagger code generation in Docker containers

+ +The `server` folder contains files to build the http server image used to serve the files referenced in the `$ref` field of Swagger `.yaml` files. + +The `codegen` folder contains files to build the code generator `swagger-codegen` used to generate the source and documentary files used to support SDRangel REST API. + +The `compose` folder contains files to build the Docker compose stack comprising the `server` and `codegen` containers. + +The SDRangel source tree is mounted in both containers as writable so the generated code can be written directly from the code generator or the Swagger files served by the http server. + +

Server

+ +Use `build.sh` to build the image. It takes the following arguments: + - `-t`: Image tag name `latest` is the default. The image is `sdrangel/swagger/server:` + - `-f`: Specify a Dockerfile (default is Dockerfile in current directory i.e. '.') + +The `run.sh` script is used to run the image on its own and is used for development only + +

Codegen

+ +Use `build.sh` to build the image. It takes the following arguments: + - `-b`: [Git repository](https://github.com/f4exb/swagger-codegen.git) branch name (default `sdrangel`) + - `-c`: Arbitrary clone label. Clone again if different from the last label (default current timestamp) + - `-t`: Docker image tag. Use git tag or commit hash (default `latest`) + - `-f`: Specify a Dockerfile (default is Dockerfile in current directory i.e. '.') + +

Compose

+ +Use `run.sh` to create or delete the Docker compose stack. It takes the following arguments: + - `-D`: Use this option to bring down the compose stack (default is to bring up). + - `-t`: Docker codegen image tag (default `latest`) + - `-T`: Docker server image tag (default `latest`) + - `-b`: SDRangel source code root path (default `/opt/build/sdrangel`) + - `-c`: Compose stack name (default `sdrangelswg`) + +The stack is composed of two containers sharing the `172.20.0.0/16` network internally. + - `sdrangel_swgserver`: The http server that listens on port `8081` serving files in `/opt/build/sdrangel/swagger/sdrangel` + - `sdrangel_swgcodegen`: The container with the Swagger code generator. The working directory is `/opt/build/sdrangel/swagger/sdrangel`. + +Use `login.sh` to start a shell in the `sdrangel_swgcodegen` container. At the prompt run `generate.sh` to generate the code from the Swagger definition files. diff --git a/swagger/docker/server/Dockerfile b/swagger/docker/server/Dockerfile new file mode 100644 index 000000000..47e6409cc --- /dev/null +++ b/swagger/docker/server/Dockerfile @@ -0,0 +1,21 @@ +FROM node:alpine as base + +# Install base packages +RUN apk update && apk add sudo + +RUN npm install -g http-server + +# Give node user sudo rights and default to it +RUN addgroup node wheel +RUN echo '%wheel ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers +USER node + +RUN sudo mkdir /opt/build \ + && sudo chown node:node /opt/build +WORKDIR /opt/build + +FROM base as codegen_server +RUN mkdir -p /opt/build/sdrangel/swagger/sdrangel + +WORKDIR /opt/build/sdrangel/swagger/sdrangel +ENTRYPOINT [ "http-server", "-p 8081", "--cors"] diff --git a/swagger/docker/server/build.sh b/swagger/docker/server/build.sh new file mode 100755 index 000000000..7f4bf0ff8 --- /dev/null +++ b/swagger/docker/server/build.sh @@ -0,0 +1,43 @@ +#!/bin/sh + +OPTIND=1 # Reset in case getopts has been used previously in the shell. + +# Get options: +show_help() { + cat << EOF + Usage: ${0##*/} [-b name] [-c label] [-t version] [-h] + Build SDRangel image. + -t tag Docker image tag version (default latest) + -f file Specify a Dockerfile (default is Dockerfile in current directory i.e. '.') + -h Print this help. +EOF +} + +image_name="sdrangel/swagger/server" +image_tag="latest" +uid=$(id -u) +docker_file="." + +while getopts "h?t:f:" opt; do + case "$opt" in + h|\?) + show_help + exit 0 + ;; + t) image_tag=${OPTARG} + ;; + f) docker_file="-f ${OPTARG} ." + ;; + esac +done + +shift $((OPTIND-1)) + +[ "${1:-}" = "--" ] && shift +# End of get options + +IMAGE_NAME=${image_name}:${image_tag} +DOCKER_BUILDKIT=1 docker build \ + --build-arg uid=${uid} \ + --target codegen_server \ + -t ${IMAGE_NAME} ${docker_file} diff --git a/swagger/docker/server/run.sh b/swagger/docker/server/run.sh new file mode 100755 index 000000000..a3a331e32 --- /dev/null +++ b/swagger/docker/server/run.sh @@ -0,0 +1,51 @@ +#!/bin/sh + +OPTIND=1 # Reset in case getopts has been used previously in the shell. + +# Get options: +show_help() { + cat << EOF + Usage: ${0##*/} [-t version] [-p port] [-h] + Run SDRangel client in a Docker container. + -i name Docker image name (default sdrangel/swagger/server) + -t tag Docker image tag version (default latest) + -c name Docker container name (default sdrangelswg_server) + -p port http port map to 8081 (default 8081) + -h Print this help. +EOF +} + +image_name="sdrangel/swagger/server" +image_tag="latest" +container_name="sdrangelswg_server" +http_port="-p 8081:8081" + +while getopts "h?gi:t:c:p:" opt; do + case "$opt" in + h|\?) + show_help + exit 0 + ;; + i) image_name=${OPTARG} + ;; + t) image_tag=${OPTARG} + ;; + c) container_name=${OPTARG} + ;; + p) http_port="-p ${OPTARG}:8081" + ;; + esac +done + +shift $((OPTIND-1)) + +[ "${1:-}" = "--" ] && shift +# End of get options + +# Run container +USER_UID=$(id -u) +docker run -it --rm \ + --name ${container_name} \ + ${http_port} \ + -v="/opt/build/sdrangel:/opt/build/sdrangel:rw" \ + ${image_name}:${image_tag} \ No newline at end of file