From 9e09e9f3fc1036d387eba0bca2945208c91583fc Mon Sep 17 00:00:00 2001 From: stephb9959 Date: Wed, 23 Mar 2022 20:52:41 -0700 Subject: [PATCH] Initial commit. --- Dockerfile | 133 ++++++++++++++++++++++++++++++++++++ docker-entrypoint.sh | 54 +++++++++++++++ owanalytics.properties.tmpl | 104 ++++++++++++++++++++++++++++ readiness_check | 65 ++++++++++++++++++ wait-for-postgres.sh | 26 +++++++ 5 files changed, 382 insertions(+) create mode 100644 Dockerfile create mode 100755 docker-entrypoint.sh create mode 100644 owanalytics.properties.tmpl create mode 100755 readiness_check create mode 100755 wait-for-postgres.sh diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..234abb7 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,133 @@ +FROM alpine:3.15 AS build-base + +RUN apk add --update --no-cache \ + make cmake g++ git \ + unixodbc-dev postgresql-dev mariadb-dev \ + librdkafka-dev boost-dev openssl-dev \ + zlib-dev nlohmann-json \ + curl-dev + +FROM build-base AS poco-build + +ADD https://api.github.com/repos/stephb9959/poco/git/refs/heads/master version.json +RUN git clone https://github.com/stephb9959/poco /poco + +WORKDIR /poco +RUN mkdir cmake-build +WORKDIR cmake-build +RUN cmake .. +RUN cmake --build . --config Release -j8 +RUN cmake --build . --target install + +FROM build-base AS cppkafka-build + +ADD https://api.github.com/repos/stephb9959/cppkafka/git/refs/heads/master version.json +RUN git clone https://github.com/stephb9959/cppkafka /cppkafka + +WORKDIR /cppkafka +RUN mkdir cmake-build +WORKDIR cmake-build +RUN cmake .. +RUN cmake --build . --config Release -j8 +RUN cmake --build . --target install + +FROM build-base AS json-schema-validator-build + +ADD https://api.github.com/repos/pboettch/json-schema-validator/git/refs/heads/master version.json +RUN git clone https://github.com/pboettch/json-schema-validator /json-schema-validator + +WORKDIR /json-schema-validator +RUN mkdir cmake-build +WORKDIR cmake-build +RUN cmake .. +RUN make +RUN make install + +FROM build-base AS fmtlib-build + +ADD https://api.github.com/repos/fmtlib/fmt/git/refs/heads/master version.json +RUN git clone https://github.com/fmtlib/fmt /fmtlib + +WORKDIR /fmtlib +RUN mkdir cmake-build +WORKDIR cmake-build +RUN cmake .. +RUN make +RUN make install + +FROM build-base AS aws-sdk-cpp-build + +ADD https://api.github.com/repos/aws/aws-sdk-cpp/git/refs/heads/main version.json +RUN git clone --recurse-submodules https://github.com/aws/aws-sdk-cpp /aws-sdk-cpp + +WORKDIR /aws-sdk-cpp +RUN mkdir cmake-build +WORKDIR cmake-build +RUN cmake .. -DBUILD_ONLY="sns;s3" \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_CXX_FLAGS="-Wno-error=stringop-overflow -Wno-error=uninitialized" \ + -DAUTORUN_UNIT_TESTS=OFF +RUN cmake --build . --config Release -j8 +RUN cmake --build . --target install + +FROM build-base AS owanalytics-build + +ADD CMakeLists.txt build /owanalytics/ +ADD cmake /owanalytics/cmake +ADD src /owanalytics/src +ADD .git /owanalytics/.git + +COPY --from=poco-build /usr/local/include /usr/local/include +COPY --from=poco-build /usr/local/lib /usr/local/lib +COPY --from=cppkafka-build /usr/local/include /usr/local/include +COPY --from=cppkafka-build /usr/local/lib /usr/local/lib +COPY --from=json-schema-validator-build /usr/local/include /usr/local/include +COPY --from=json-schema-validator-build /usr/local/lib /usr/local/lib +COPY --from=aws-sdk-cpp-build /usr/local/include /usr/local/include +COPY --from=aws-sdk-cpp-build /usr/local/lib /usr/local/lib + +COPY --from=fmtlib-build /usr/local/include /usr/local/include +COPY --from=fmtlib-build /usr/local/lib /usr/local/lib + +WORKDIR /owanalytics +RUN mkdir cmake-build +WORKDIR /owanalytics/cmake-build +RUN cmake .. +RUN cmake --build . --config Release -j8 + +FROM alpine:3.15 + +ENV OWANALYTICS_USER=owanalytics \ + OWANALYTICS_ROOT=/owanalytics-data \ + OWANALYTICS_CONFIG=/owanalytics-data + +RUN addgroup -S "$OWANALYTICS_USER" && \ + adduser -S -G "$OWANALYTICS_USER" "$OWANALYTICS_USER" + +RUN mkdir /openwifi +RUN mkdir -p "$OWANALYTICS_ROOT" "$OWANALYTICS_CONFIG" && \ + chown "$OWANALYTICS_USER": "$OWANALYTICS_ROOT" "$OWANALYTICS_CONFIG" + +RUN apk add --update --no-cache librdkafka su-exec gettext ca-certificates bash jq curl \ + mariadb-connector-c libpq unixodbc postgresql-client + +COPY readiness_check /readiness_check +COPY test_scripts/curl/cli /cli + +COPY owanalytics.properties.tmpl / +COPY docker-entrypoint.sh / +COPY wait-for-postgres.sh / +RUN wget https://raw.githubusercontent.com/Telecominfraproject/wlan-cloud-ucentral-deploy/main/docker-compose/certs/restapi-ca.pem \ + -O /usr/local/share/ca-certificates/restapi-ca-selfsigned.pem + +COPY --from=owanalytics-build /owanalytics/cmake-build/owanalytics /openwifi/owanalytics +COPY --from=cppkafka-build /cppkafka/cmake-build/src/lib/* /usr/local/lib +COPY --from=poco-build /poco/cmake-build/lib/* /usr/local/lib +COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-core/libaws-cpp-sdk-core.so /usr/local/lib +COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-s3/libaws-cpp-sdk-s3.so /usr/local/lib +COPY --from=aws-sdk-cpp-build /aws-sdk-cpp/cmake-build/aws-cpp-sdk-sns/libaws-cpp-sdk-sns.so /usr/local/lib + +EXPOSE 16005 17005 16105 + +ENTRYPOINT ["/docker-entrypoint.sh"] +CMD ["/openwifi/owanalytics"] diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100755 index 0000000..c921440 --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,54 @@ +#!/bin/sh +set -e + +if [ "$SELFSIGNED_CERTS" = 'true' ]; then + update-ca-certificates +fi + +if [[ "$TEMPLATE_CONFIG" = 'true' && ! -f "$OWANALYTICS_CONFIG"/owanalytics.properties ]]; then + RESTAPI_HOST_ROOTCA=${RESTAPI_HOST_ROOTCA:-"\$OWANALYTICS_ROOT/certs/restapi-ca.pem"} \ + RESTAPI_HOST_PORT=${RESTAPI_HOST_PORT:-"16009"} \ + RESTAPI_HOST_CERT=${RESTAPI_HOST_CERT:-"\$OWANALYTICS_ROOT/certs/restapi-cert.pem"} \ + RESTAPI_HOST_KEY=${RESTAPI_HOST_KEY:-"\$OWANALYTICS_ROOT/certs/restapi-key.pem"} \ + RESTAPI_HOST_KEY_PASSWORD=${RESTAPI_HOST_KEY_PASSWORD:-"mypassword"} \ + INTERNAL_RESTAPI_HOST_ROOTCA=${INTERNAL_RESTAPI_HOST_ROOTCA:-"\$OWANALYTICS_ROOT/certs/restapi-ca.pem"} \ + INTERNAL_RESTAPI_HOST_PORT=${INTERNAL_RESTAPI_HOST_PORT:-"17009"} \ + INTERNAL_RESTAPI_HOST_CERT=${INTERNAL_RESTAPI_HOST_CERT:-"\$OWANALYTICS_ROOT/certs/restapi-cert.pem"} \ + INTERNAL_RESTAPI_HOST_KEY=${INTERNAL_RESTAPI_HOST_KEY:-"\$OWANALYTICS_ROOT/certs/restapi-key.pem"} \ + INTERNAL_RESTAPI_HOST_KEY_PASSWORD=${INTERNAL_RESTAPI_HOST_KEY_PASSWORD:-"mypassword"} \ + FIRMWARE_UPDATER_UPGRADE=${FIRMWARE_UPDATER_UPGRADE:-"yes"} \ + FIRMWARE_UPDATER_RCONLY=${FIRMWARE_UPDATER_RCONLY:-"no"} \ + SERVICE_KEY=${SERVICE_KEY:-"\$OWANALYTICS_ROOT/certs/restapi-key.pem"} \ + SERVICE_KEY_PASSWORD=${SERVICE_KEY_PASSWORD:-"mypassword"} \ + SYSTEM_DATA=${SYSTEM_DATA:-"\$OWANALYTICS_ROOT/data"} \ + SYSTEM_URI_PRIVATE=${SYSTEM_URI_PRIVATE:-"https://localhost:17009"} \ + SYSTEM_URI_PUBLIC=${SYSTEM_URI_PUBLIC:-"https://localhost:16009"} \ + SYSTEM_URI_UI=${SYSTEM_URI_UI:-"http://localhost"} \ + KAFKA_ENABLE=${KAFKA_ENABLE:-"true"} \ + KAFKA_BROKERLIST=${KAFKA_BROKERLIST:-"localhost:9092"} \ + KAFKA_SSL_CA_LOCATION=${KAFKA_SSL_CA_LOCATION:-""} \ + KAFKA_SSL_CERTIFICATE_LOCATION=${KAFKA_SSL_CERTIFICATE_LOCATION:-""} \ + KAFKA_SSL_KEY_LOCATION=${KAFKA_SSL_KEY_LOCATION:-""} \ + KAFKA_SSL_KEY_PASSWORD=${KAFKA_SSL_KEY_PASSWORD:-""} \ + STORAGE_TYPE=${STORAGE_TYPE:-"sqlite"} \ + STORAGE_TYPE_POSTGRESQL_HOST=${STORAGE_TYPE_POSTGRESQL_HOST:-"localhost"} \ + STORAGE_TYPE_POSTGRESQL_USERNAME=${STORAGE_TYPE_POSTGRESQL_USERNAME:-"owanalytics"} \ + STORAGE_TYPE_POSTGRESQL_PASSWORD=${STORAGE_TYPE_POSTGRESQL_PASSWORD:-"owanalytics"} \ + STORAGE_TYPE_POSTGRESQL_DATABASE=${STORAGE_TYPE_POSTGRESQL_DATABASE:-"owanalytics"} \ + STORAGE_TYPE_POSTGRESQL_PORT=${STORAGE_TYPE_POSTGRESQL_PORT:-"5432"} \ + STORAGE_TYPE_MYSQL_HOST=${STORAGE_TYPE_MYSQL_HOST:-"localhost"} \ + STORAGE_TYPE_MYSQL_USERNAME=${STORAGE_TYPE_MYSQL_USERNAME:-"owanalytics"} \ + STORAGE_TYPE_MYSQL_PASSWORD=${STORAGE_TYPE_MYSQL_PASSWORD:-"owanalytics"} \ + STORAGE_TYPE_MYSQL_DATABASE=${STORAGE_TYPE_MYSQL_DATABASE:-"owanalytics"} \ + STORAGE_TYPE_MYSQL_PORT=${STORAGE_TYPE_MYSQL_PORT:-"3306"} \ + envsubst < /owanalytics.properties.tmpl > $OWANALYTICS_CONFIG/owanalytics.properties +fi + +if [ "$1" = '/openwifi/owanalytics' -a "$(id -u)" = '0' ]; then + if [ "$RUN_CHOWN" = 'true' ]; then + chown -R "$OWANALYTICS_USER": "$OWANALYTICS_ROOT" "$OWANALYTICS_CONFIG" + fi + exec su-exec "$OWANALYTICS_USER" "$@" +fi + +exec "$@" diff --git a/owanalytics.properties.tmpl b/owanalytics.properties.tmpl new file mode 100644 index 0000000..1b51d4d --- /dev/null +++ b/owanalytics.properties.tmpl @@ -0,0 +1,104 @@ +# +# uCentral protocol server for devices. This is where you point +# all your devices. You can replace the * for address by the specific +# address of one of your interfaces +# + +# +# REST API access +# +openwifi.restapi.host.0.backlog = 100 +openwifi.restapi.host.0.security = relaxed +openwifi.restapi.host.0.rootca = ${RESTAPI_HOST_ROOTCA} +openwifi.restapi.host.0.address = * +openwifi.restapi.host.0.port = ${RESTAPI_HOST_PORT} +openwifi.restapi.host.0.cert = ${RESTAPI_HOST_CERT} +openwifi.restapi.host.0.key = ${RESTAPI_HOST_KEY} +openwifi.restapi.host.0.key.password = ${RESTAPI_HOST_KEY_PASSWORD} + +openwifi.internal.restapi.host.0.backlog = 100 +openwifi.internal.restapi.host.0.security = relaxed +openwifi.internal.restapi.host.0.rootca = ${INTERNAL_RESTAPI_HOST_ROOTCA} +openwifi.internal.restapi.host.0.address = * +openwifi.internal.restapi.host.0.port = ${INTERNAL_RESTAPI_HOST_PORT} +openwifi.internal.restapi.host.0.cert = ${INTERNAL_RESTAPI_HOST_CERT} +openwifi.internal.restapi.host.0.key = ${INTERNAL_RESTAPI_HOST_KEY} +openwifi.internal.restapi.host.0.key.password = ${INTERNAL_RESTAPI_HOST_KEY_PASSWORD} + +firmware.updater.upgrade = ${FIRMWARE_UPDATER_UPGRADE} +firmware.updater.rconly = ${FIRMWARE_UPDATER_RCONLY} + +# +# Generic section that all microservices must have +# +openwifi.service.key = ${SERVICE_KEY} +openwifi.service.key.password = ${SERVICE_KEY_PASSWORD} +openwifi.system.data = ${SYSTEM_DATA} +openwifi.system.debug = false +openwifi.system.uri.private = ${SYSTEM_URI_PRIVATE} +openwifi.system.uri.public = ${SYSTEM_URI_PUBLIC} +openwifi.system.commandchannel = /tmp/app.ow.analytics +openwifi.system.uri.ui = ${SYSTEM_URI_UI} + +############################# +# Generic information for all micro services +############################# +# +# NLB Support +# +alb.enable = true +alb.port = 16109 + +# +# Kafka +# +openwifi.kafka.group.id = analytics +openwifi.kafka.client.id = analytic1 +openwifi.kafka.enable = ${KAFKA_ENABLE} +openwifi.kafka.brokerlist = ${KAFKA_BROKERLIST} +openwifi.kafka.auto.commit = false +openwifi.kafka.queue.buffering.max.ms = 50 +openwifi.kafka.ssl.ca.location = ${KAFKA_SSL_CA_LOCATION} +openwifi.kafka.ssl.certificate.location = ${KAFKA_SSL_CERTIFICATE_LOCATION} +openwifi.kafka.ssl.key.location = ${KAFKA_SSL_KEY_LOCATION} +openwifi.kafka.ssl.key.password = ${KAFKA_SSL_KEY_PASSWORD} + +# +# This section select which form of persistence you need +# Only one selected at a time. If you select multiple, this service will die if a horrible +# death and might make your beer flat. +# +storage.type = ${STORAGE_TYPE} + +storage.type.sqlite.db = analytics.db +storage.type.sqlite.idletime = 120 +storage.type.sqlite.maxsessions = 128 + +storage.type.postgresql.maxsessions = 64 +storage.type.postgresql.idletime = 60 +storage.type.postgresql.host = ${STORAGE_TYPE_POSTGRESQL_HOST} +storage.type.postgresql.username = ${STORAGE_TYPE_POSTGRESQL_USERNAME} +storage.type.postgresql.password = ${STORAGE_TYPE_POSTGRESQL_PASSWORD} +storage.type.postgresql.database = ${STORAGE_TYPE_POSTGRESQL_DATABASE} +storage.type.postgresql.port = ${STORAGE_TYPE_POSTGRESQL_PORT} +storage.type.postgresql.connectiontimeout = 60 + +storage.type.mysql.maxsessions = 64 +storage.type.mysql.idletime = 60 +storage.type.mysql.host = ${STORAGE_TYPE_MYSQL_HOST} +storage.type.mysql.username = ${STORAGE_TYPE_MYSQL_USERNAME} +storage.type.mysql.password = ${STORAGE_TYPE_MYSQL_PASSWORD} +storage.type.mysql.database = ${STORAGE_TYPE_MYSQL_DATABASE} +storage.type.mysql.port = ${STORAGE_TYPE_MYSQL_PORT} +storage.type.mysql.connectiontimeout = 60 + + +######################################################################## +######################################################################## +# +# Logging: please leave as is for now. +# +######################################################################## +logging.type = console +logging.path = $OWANALYTICS_ROOT/logs +logging.level = debug diff --git a/readiness_check b/readiness_check new file mode 100755 index 0000000..c0f2704 --- /dev/null +++ b/readiness_check @@ -0,0 +1,65 @@ +#!/bin/bash +set -e + +if [[ "$(which jq)" == "" ]] +then + echo "You need the package jq installed to use this script." + exit 1 +fi + +if [[ "$(which curl)" == "" ]] +then + echo "You need the package curl installed to use this script." + exit 1 +fi + +if [[ "${READINESS_METHOD}" == "systeminfo" ]] +then + if [[ "${OWSEC}" == "" ]] + then + echo "You must set the variable OWSEC in order to use this script. Something like" + echo "OWSEC=security.isp.com:16001" + exit 1 + fi + + if [[ "${OWSEC_USERNAME}" == "" ]] + then + echo "You must set the variable OWSEC_USERNAME in order to use this script. Something like" + echo "OWSEC_USERNAME=tip@ucentral.com" + exit 1 + fi + + if [[ "${OWSEC_PASSWORD}" == "" ]] + then + echo "You must set the variable OWSEC_PASSWORD in order to use this script. Something like" + echo "OWSEC_PASSWORD=openwifi" + exit 1 + fi + + # Get OAuth token from OWSEC and cache it or use cached one + payload="{ \"userId\" : \"$OWSEC_USERNAME\" , \"password\" : \"$OWSEC_PASSWORD\" }" + if [[ -f "/tmp/token" ]] + then + token=$(cat /tmp/token) + else + token=$(curl ${FLAGS} -X POST -H "Content-Type: application/json" -d "$payload" "https://${OWSEC}/api/v1/oauth2" | jq -r '.access_token') + fi + if [[ "${token}" == "" ]] + then + echo "Could not login. Please verify the host and username/password." + exit 13 + fi + echo -n $token > /tmp/token + + # Make systeminfo request to the local owanalytics instance + export RESTAPI_PORT=$(grep 'openwifi.restapi.host.0.port' $OWANALYTICS_CONFIG/owanalytics.properties | awk -F '=' '{print $2}' | xargs | envsubst) + curl ${FLAGS} -k -X GET "https://localhost:$RESTAPI_PORT/api/v1/system?command=info" \ + -H "accept: application/json" \ + -H "Authorization: Bearer ${token}" > /tmp/result.json + exit_code=$? + jq < /tmp/result.json + exit $exit_code +else + export ALB_PORT=$(grep 'alb.port' $OWANALYTICS_CONFIG/owanalytics.properties | awk -F '=' '{print $2}' | xargs | envsubst) + curl localhost:$ALB_PORT +fi diff --git a/wait-for-postgres.sh b/wait-for-postgres.sh new file mode 100755 index 0000000..17b51c0 --- /dev/null +++ b/wait-for-postgres.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# wait-for-postgres.sh + +set -e + +host="$1" +shift + +export PGUSER=$(grep 'storage.type.postgresql.username' $OWANALYTICS_CONFIG/owprov.properties | awk -F '= ' '{print $2}') +export PGPASSWORD=$(grep 'storage.type.postgresql.password' $OWANALYTICS_CONFIG/owprov.properties | awk -F '= ' '{print $2}') + +until psql -h "$host" -c '\q'; do + >&2 echo "Postgres is unavailable - sleeping" + sleep 1 +done + +>&2 echo "Postgres is up - executing command" + +if [ "$1" = '/openwifi/owanalytics' -a "$(id -u)" = '0' ]; then + if [ "$RUN_CHOWN" = 'true' ]; then + chown -R "$OWANALYTICS_USER": "$OWANALYTICS_ROOT" "$OWANALYTICS_CONFIG" + fi + exec su-exec "$OWANALYTICS_USER" "$@" +fi + +exec "$@"