diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..e5bb499
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,29 @@
+name: "docker-debug"
+
+on: push
+
+jobs:
+ build-images:
+ runs-on: ubuntu-latest
+ env:
+ DOCKER_REPO: "seemscloud"
+ steps:
+ - name: "[Repository] Clone"
+ uses: actions/checkout@v2
+ - name: "[Login] Docker Hub"
+ uses: docker/login-action@v3
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+ - name: "[Setup] JDK 17"
+ uses: actions/setup-java@v3
+ with:
+ java-version: '17'
+ distribution: 'temurin'
+ architecture: x64
+ - name: "[Build] Maven Clean Package"
+ run: |
+ mvn clean package
+ git config --global user.email "versioner@seems.cloud"
+ git config --global user.name "VersionerBot"
+ mvn clean install
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e673575
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.idea/
+target/
\ No newline at end of file
diff --git a/images/debug/Dockerfile b/images/debug/Dockerfile
new file mode 100644
index 0000000..28d1ae5
--- /dev/null
+++ b/images/debug/Dockerfile
@@ -0,0 +1,29 @@
+FROM alpine:latest
+
+ARG USER_HOME="/tmp/debug"
+ARG USER_NAME="debug"
+ARG USER_UID="1000"
+ARG GROUP_NAME="${USER_NAME}"
+ARG GROUP_UID="${USER_UID}"
+
+ARG KUBECTL_VERSION="1.25.3"
+
+RUN addgroup -g "${GROUP_UID}" "${GROUP_NAME}" && \
+ adduser -G "${GROUP_NAME}" -s /bin/bash -u "${USER_UID}" -h "${USER_HOME}" "${USER_NAME}" -D
+
+RUN apk update && \
+ apk add bash
+
+SHELL ["/bin/bash", "-c"]
+
+RUN apk add bind-tools iperf3 busybox-extras curl fio
+
+RUN wget "https://dl.k8s.io/release/v${KUBECTL_VERSION}/bin/linux/amd64/kubectl" -O /usr/local/bin/kubectl && \
+ chmod 0755 /usr/local/bin/kubectl
+
+COPY docker-entrypoint.sh /
+
+WORKDIR "${USER_HOME}"
+USER "${USER_NAME}"
+
+ENTRYPOINT ["/bin/bash", "/docker-entrypoint.sh"]
diff --git a/images/debug/docker-entrypoint.sh b/images/debug/docker-entrypoint.sh
new file mode 100644
index 0000000..e1d7434
--- /dev/null
+++ b/images/debug/docker-entrypoint.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+while true; do
+ true
+done
diff --git a/images/debug/pom.xml b/images/debug/pom.xml
new file mode 100644
index 0000000..c642a24
--- /dev/null
+++ b/images/debug/pom.xml
@@ -0,0 +1,61 @@
+
+
+
+ 4.0.0
+ pom
+
+ cicd.images.debug
+ com.seemscloud.cicd.images.debug
+
+
+ cicd.images
+ com.seemscloud.cicd.images
+ 1.4.2-SNAPSHOT
+
+
+
+
+
+ io.fabric8
+ docker-maven-plugin
+
+ true
+
+
+ debug
+ ${env.DOCKER_REPO}/debug:latest
+
+ ${project.basedir}
+ @
+
+
+
+ debug
+ ${env.DOCKER_REPO}/debug:${project.version}
+
+ ${project.basedir}
+ @
+
+
+
+
+
+
+ build docker
+ package
+
+ build
+
+
+
+ push docker
+ package
+
+ push
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/images/fastapi/Dockerfile b/images/fastapi/Dockerfile
new file mode 100644
index 0000000..45f8036
--- /dev/null
+++ b/images/fastapi/Dockerfile
@@ -0,0 +1,31 @@
+FROM python:3.11-alpine
+
+ARG USER_HOME="/app"
+ARG USER_NAME="app"
+ARG USER_UID="1000"
+ARG GROUP_NAME="${USER_NAME}"
+ARG GROUP_UID="${USER_UID}"
+
+ENV PATH="${PATH}:${USER_HOME}/.local/bin/"
+
+RUN addgroup -g "${GROUP_UID}" "${GROUP_NAME}" && \
+ adduser -G "${GROUP_NAME}" -s /bin/bash -u "${USER_UID}" -h "${USER_HOME}" "${USER_NAME}" -D
+
+RUN apk update && \
+ apk add bash
+
+SHELL ["/bin/bash", "-c"]
+
+RUN apk add bind-tools iperf3 busybox-extras curl fio
+
+COPY docker-entrypoint.sh /
+
+WORKDIR "${USER_HOME}"
+USER "${USER_NAME}"
+
+COPY ./src/* .
+
+RUN python3 -m pip install --upgrade pip && \
+ python3 -m pip install --upgrade hypercorn uvicorn fastapi
+
+ENTRYPOINT ["/bin/bash", "/docker-entrypoint.sh"]
diff --git a/images/fastapi/docker-entrypoint.sh b/images/fastapi/docker-entrypoint.sh
new file mode 100644
index 0000000..3eb072c
--- /dev/null
+++ b/images/fastapi/docker-entrypoint.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+CONF_COLORS="$CONF_COLORS"
+
+function logger_format() {
+ DATE=$(date +"%Y-%m-%d %H:%M:%S,%3N")
+
+ if [[ "${CONF_COLORS}" == "true" ]]; then
+ echo -e "${DATE} \e[${3}m${1}\e[m\t ${2}"
+ else
+ echo -e "${DATE} ${1}\t ${2}"
+ fi
+}
+
+function logger_msg() {
+ if [ "${2}" == "error" ]; then
+ logger_format "ERROR" "${1}" "91"
+ elif [ "${2}" == "success" ]; then
+ logger_format "SUCCESS" "${1}" "92"
+ elif [ "${2}" == "warning" ]; then
+ logger_format "WARNING" "${1}" "93"
+ elif [ "${2}" == "info" ]; then
+ logger_format "INFO" "${1}" "96"
+ else
+ logger_format "LOGGER" "Incorrect logger type: '${2}'.." "31" && exit 4
+ fi
+}
+
+function logger() {
+ [ "${#}" -lt 2 ] || [ "${#}" -gt 2 ] && exit 1
+
+ logger_msg "${2}" "${1}"
+}
+
+# Main
+
+if [ "${SERVER_TYPE}" == "hypercorn" ]; then
+ logger info "Starting '${SERVER_TYPE}' server.."
+
+ hypercorn --bind "0.0.0.0:${SERVER_PORT}" app:app
+elif [ "${SERVER_TYPE}" == "uvicorn" ]; then
+ logger info "Starting '${SERVER_TYPE}' server.."
+
+ uvicorn --host "0.0.0.0" --port "${SERVER_PORT}" app:app
+fi
diff --git a/images/fastapi/pom.xml b/images/fastapi/pom.xml
new file mode 100644
index 0000000..a0d0f3b
--- /dev/null
+++ b/images/fastapi/pom.xml
@@ -0,0 +1,61 @@
+
+
+
+ 4.0.0
+ pom
+
+ cicd.images.fastapi
+ com.seemscloud.cicd.images.fastapi
+
+
+ cicd.images
+ com.seemscloud.cicd.images
+ 1.4.2-SNAPSHOT
+
+
+
+
+
+ io.fabric8
+ docker-maven-plugin
+
+ true
+
+
+ fastapi
+ seemscloud/fastapi:latest
+
+ ${project.basedir}
+ @
+
+
+
+ fastapi
+ seemscloud/fastapi:${project.version}
+
+ ${project.basedir}
+ @
+
+
+
+
+
+
+ build docker
+ package
+
+ build
+
+
+
+ push docker
+ deploy
+
+ push
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/images/fastapi/src/app.py b/images/fastapi/src/app.py
new file mode 100644
index 0000000..7071c09
--- /dev/null
+++ b/images/fastapi/src/app.py
@@ -0,0 +1,8 @@
+from fastapi import FastAPI
+
+app = FastAPI()
+
+
+@app.get("/")
+async def root():
+ return {"message": "Hello world!"}
diff --git a/images/grpc-client/Dockerfile b/images/grpc-client/Dockerfile
new file mode 100644
index 0000000..f1765a6
--- /dev/null
+++ b/images/grpc-client/Dockerfile
@@ -0,0 +1,29 @@
+FROM python:3.10-alpine
+
+ARG USER_HOME="/app"
+ARG USER_NAME="grpc"
+ARG USER_UID="1000"
+ARG GROUP_NAME="${USER_NAME}"
+ARG GROUP_UID="${USER_UID}"
+
+ENV GRPC_DEFAULT_SSL_ROOTS_FILE_PATH="${USER_HOME}/ca.crt.pem"
+
+RUN addgroup -g "${GROUP_UID}" "${GROUP_NAME}" && \
+ adduser -G "${GROUP_NAME}" -s /bin/bash -u "${USER_UID}" -h "${USER_HOME}" "${USER_NAME}" -D
+
+RUN apk update && \
+ apk add bash
+
+SHELL ["/bin/bash", "-c"]
+
+COPY docker-entrypoint.sh /
+
+WORKDIR "${USER_HOME}"
+USER "${USER_NAME}"
+
+RUN python3 -m pip install --upgrade pip && \
+ python3 -m pip install --upgrade grpcio grpcio-tools
+
+COPY src .
+
+ENTRYPOINT ["/bin/bash", "/docker-entrypoint.sh"]
\ No newline at end of file
diff --git a/images/grpc-client/docker-entrypoint.sh b/images/grpc-client/docker-entrypoint.sh
new file mode 100644
index 0000000..a4fb851
--- /dev/null
+++ b/images/grpc-client/docker-entrypoint.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+
+CONF_COLORS="$CONF_COLORS"
+
+function logger_format() {
+ DATE=$(date +"%Y-%m-%d %H:%M:%S,%3N")
+
+ if [[ "${CONF_COLORS}" == "true" ]]; then
+ echo -e "${DATE} \e[${3}m${1}\e[m\t ${2}"
+ else
+ echo -e "${DATE} ${1}\t ${2}"
+ fi
+}
+
+function logger_msg() {
+ if [ "${2}" == "error" ]; then
+ logger_format "ERROR" "${1}" "91"
+ elif [ "${2}" == "success" ]; then
+ logger_format "SUCCESS" "${1}" "92"
+ elif [ "${2}" == "warning" ]; then
+ logger_format "WARNING" "${1}" "93"
+ elif [ "${2}" == "info" ]; then
+ logger_format "INFO" "${1}" "96"
+ else
+ logger_format "LOGGER" "Incorrect logger type: '${2}'.." "31" && exit 4
+ fi
+}
+
+function logger() {
+ [ "${#}" -lt 2 ] || [ "${#}" -gt 2 ] && exit 1
+
+ logger_msg "${2}" "${1}"
+}
+
+# Defaults
+
+if [ -z "${ENDPOINT}" ]; then
+ logger info "'ENDPOINT' is not set, using default endpoint 'localhost:9000'"
+
+ ENDPOINT="localhost:9000"
+fi
+
+# Main
+
+logger info "Connection to '${ENDPOINT}', TLS: '${USE_TLS}'.."
+python3 -u client.py
diff --git a/images/grpc-client/pom.xml b/images/grpc-client/pom.xml
new file mode 100644
index 0000000..109455b
--- /dev/null
+++ b/images/grpc-client/pom.xml
@@ -0,0 +1,61 @@
+
+
+
+ 4.0.0
+ pom
+
+ cicd.images.grpc-client
+ com.seemscloud.cicd.images.grpc-client
+
+
+ cicd.images
+ com.seemscloud.cicd.images
+ 1.4.2-SNAPSHOT
+
+
+
+
+
+ io.fabric8
+ docker-maven-plugin
+
+ true
+
+
+ grpc-client
+ seemscloud/grpc-client:latest
+
+ ${project.basedir}
+ @
+
+
+
+ grpc-client
+ seemscloud/grpc-client:${project.version}
+
+ ${project.basedir}
+ @
+
+
+
+
+
+
+ build docker
+ package
+
+ build
+
+
+
+ push docker
+ deploy
+
+ push
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/images/grpc-client/src/README.md b/images/grpc-client/src/README.md
new file mode 100644
index 0000000..8603e69
--- /dev/null
+++ b/images/grpc-client/src/README.md
@@ -0,0 +1,6 @@
+```bash
+export USE_TLS="true"
+export ENDPOINT="localhost:9443"
+
+python3 client.py
+```
\ No newline at end of file
diff --git a/images/grpc-client/src/ca.crt.pem b/images/grpc-client/src/ca.crt.pem
new file mode 100644
index 0000000..f5c9af0
--- /dev/null
+++ b/images/grpc-client/src/ca.crt.pem
@@ -0,0 +1,32 @@
+-----BEGIN CERTIFICATE-----
+MIIFizCCA3OgAwIBAgIUKopXQejrND/MAJGQHsbVWmB0ViwwDQYJKoZIhvcNAQEL
+BQAwVTELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB01hem92aWExDzANBgNVBAcMBldh
+cnNhdzEUMBIGA1UECgwLU2VlbXMgQ2xvdWQxDTALBgNVBAsMBFJvb3QwHhcNMjIx
+MjE5MjAxMDU3WhcNMzIxMjE2MjAxMDU3WjBVMQswCQYDVQQGEwJVUzEQMA4GA1UE
+CAwHTWF6b3ZpYTEPMA0GA1UEBwwGV2Fyc2F3MRQwEgYDVQQKDAtTZWVtcyBDbG91
+ZDENMAsGA1UECwwEUm9vdDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
+AKhHHO6eb9Zk1B3MFUIg7ntUfs6l5TyPUi+vKn+/Jeu9eOmJX4skaHMGUh0fKF0z
+FSQwXRuqO1okxG/c6AHtBgf6afHC620i6Pv+kOLEzEa3rL1ij34bCAccHREGHuyO
+9u2T3IwacASZYdTvI6biXvRQq1x3zRCT+VWCuNoPbzet6GZ2h69IWgLZKFwLDdFU
+AGLcwS8E7oLabxEZ4X8W9V9aPmMJczAxfXSAgewx4G71Z1rdIQ6WD03fOIKNeeBo
+oJ+LGKbD9NYz7F6Gmw4ngPRYWqVUogi1qRuTOd7twOKw/PZzm0nf/g0o7m9ssQZM
+WmFVdbQlsY4w0RLWZYd7kCcyTleBTZDgZFSfc1ynMmCKQvKV4PZaNCprKGtRHn2L
+/80nY1NxQfgLN6w2aMW6y2Ps4wAp+LnBL1PtOUcGO2DQetK+7Y6a1ATnVH+zm4di
+NXKDsYomgLUMqcdT+cCrdqQwpAFzNihC3v7U8xopuIdfmCpIHYPlTxBDi2wmQ93K
+1XrEScMf7knAEgR7Ar5r0K4U79wx6SHc/Unxz/VzRI26Apnv3pIOi831zO4WScPg
+/ydskvZegTCHwBov+BlZEzFDiVj6CCbM6cKj7RoMUyCmrbDb2B6BN+NmRIkDLJht
+4eEhbLaF4sE8nQq0Xa9ZqI3rFJTfYC8kJrQPeQgf45v5AgMBAAGjUzBRMB0GA1Ud
+DgQWBBSNd8vAscwWdDR7AV8slr98YMd9xjAfBgNVHSMEGDAWgBSNd8vAscwWdDR7
+AV8slr98YMd9xjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQBy
+XOd7xcEw14hIqHYJOZ9Kw5L6OlTIZg9u1+snAcYKWi0hWPJFV/lC+oonl4MvrUYQ
+ZXdXxL2Po3p2uyxpPpyaV0Rle4Alrz9ViOQwmqvUWzft3mLvpIJYnRRwXa2d5xX7
+Rz2x/DDRwacI1ew6v+D3CHm1LzILJsHwuk89sstWix48inYb4jFdHqvmfaK4XxCK
+hg6w95jOKd3mBaOgciqkjROQDPQqjjFvJJvjWe5BWNFaiyG1zZMBNumstLni3t0R
+d1pqhuZ4wnSUrybDGr7esYeECdApnkn3ryHjLBMS684/lMRpoyTWXaGPK/MePhoo
+Y26SWssjtU0sw9opp069j5FwLEjLyovarNUY+i3H43aihhwJgWyrZT2dugdHEQp+
+FgJH9TXIXQxzur4xbUH50s13bHg8jYYGBwLruzvT4zOyRib7ZjvRZca/J9Pombca
+Co2tQwulncbVh4+p8Vt6a10NmAlLetpylvpG/bU81T7wkB7QKwK4kGji20CvyBN0
+UfSitl9xwdsDmN9SjDOoeSNOnIgaE3FUyYq4U6eZbuvyojllZQtE+iWJvfOffaI8
+Dvm9lU52+fzpPR3kf0kXCfaryacEieQzxu7xW4DdjMosaHc2BGwPrnAdMtiFKsIH
+LYlo25/dUfiI7D6ZnbXLTpypH1FYYFZBGoiIVKAK3w==
+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/images/grpc-client/src/client.py b/images/grpc-client/src/client.py
new file mode 100644
index 0000000..9af0655
--- /dev/null
+++ b/images/grpc-client/src/client.py
@@ -0,0 +1,25 @@
+import os
+import time
+
+import grpc.experimental
+
+protos, services = grpc.protos_and_services("helloworld.proto")
+
+name = "Lorem"
+message = "Ping!"
+
+endpoint = os.environ["ENDPOINT"]
+
+if __name__ == "__main__":
+ request = protos.HelloRequest(name=name, message=message)
+ while True:
+ if 'USE_TLS' in os.environ and os.environ["USE_TLS"] == "true":
+ response = services.Greeter.SayHello(request, endpoint, insecure=False)
+ else:
+ response = services.Greeter.SayHello(request, endpoint, insecure=True)
+
+ print("Sent '{}' as '{}' to '{}'".format(message, name, endpoint))
+ print("Received '{}', from '{}' from '{}'".format(response.message, response.name, endpoint))
+ print()
+
+ time.sleep(1)
diff --git a/images/grpc-client/src/helloworld.proto b/images/grpc-client/src/helloworld.proto
new file mode 100644
index 0000000..119dc1e
--- /dev/null
+++ b/images/grpc-client/src/helloworld.proto
@@ -0,0 +1,17 @@
+syntax = "proto3";
+
+package helloworld;
+
+service Greeter {
+ rpc SayHello (HelloRequest) returns (HelloReply) {}
+}
+
+message HelloRequest {
+ string name = 1;
+ string message = 2;
+}
+
+message HelloReply {
+ string name = 1;
+ string message = 2;
+}
\ No newline at end of file
diff --git a/images/grpc-server/Dockerfile b/images/grpc-server/Dockerfile
new file mode 100644
index 0000000..d47cbc9
--- /dev/null
+++ b/images/grpc-server/Dockerfile
@@ -0,0 +1,27 @@
+FROM python:3.10-alpine
+
+ARG USER_HOME="/app"
+ARG USER_NAME="grpc"
+ARG USER_UID="1000"
+ARG GROUP_NAME="${USER_NAME}"
+ARG GROUP_UID="${USER_UID}"
+
+RUN addgroup -g "${GROUP_UID}" "${GROUP_NAME}" && \
+ adduser -G "${GROUP_NAME}" -s /bin/bash -u "${USER_UID}" -h "${USER_HOME}" "${USER_NAME}" -D
+
+RUN apk update && \
+ apk add bash
+
+SHELL ["/bin/bash", "-c"]
+
+COPY docker-entrypoint.sh /
+
+WORKDIR "${USER_HOME}"
+USER "${USER_NAME}"
+
+RUN python3 -m pip install --upgrade pip && \
+ python3 -m pip install --upgrade grpcio grpcio-tools grpcio-reflection grpcio-health-checking
+
+COPY src .
+
+ENTRYPOINT ["/bin/bash", "/docker-entrypoint.sh"]
\ No newline at end of file
diff --git a/images/grpc-server/docker-entrypoint.sh b/images/grpc-server/docker-entrypoint.sh
new file mode 100644
index 0000000..1a8a757
--- /dev/null
+++ b/images/grpc-server/docker-entrypoint.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+CONF_COLORS="$CONF_COLORS"
+
+function logger_format() {
+ DATE=$(date +"%Y-%m-%d %H:%M:%S,%3N")
+
+ if [[ "${CONF_COLORS}" == "true" ]]; then
+ echo -e "${DATE} \e[${3}m${1}\e[m\t ${2}"
+ else
+ echo -e "${DATE} ${1}\t ${2}"
+ fi
+}
+
+function logger_msg() {
+ if [ "${2}" == "error" ]; then
+ logger_format "ERROR" "${1}" "91"
+ elif [ "${2}" == "success" ]; then
+ logger_format "SUCCESS" "${1}" "92"
+ elif [ "${2}" == "warning" ]; then
+ logger_format "WARNING" "${1}" "93"
+ elif [ "${2}" == "info" ]; then
+ logger_format "INFO" "${1}" "96"
+ else
+ logger_format "LOGGER" "Incorrect logger type: '${2}'.." "31" && exit 4
+ fi
+}
+
+function logger() {
+ [ "${#}" -lt 2 ] || [ "${#}" -gt 2 ] && exit 1
+
+ logger_msg "${2}" "${1}"
+}
+
+# Defaults
+
+if [ -z "${LISTEN_PORT}" ]; then
+ logger info "'LISTEN_PORT' is not set, using default port '9000'"
+
+ LISTEN_PORT="9000"
+fi
+
+# Main
+
+logger info "Starting unsecured port on '${LISTEN_PORT}'.."
+
+if [ ! -z "${LISTEN_PORT_TLS}" ]; then
+ logger info "Starting secured port on '${LISTEN_PORT_TLS}'.."
+fi
+
+python3 -u server.py
diff --git a/images/grpc-server/pom.xml b/images/grpc-server/pom.xml
new file mode 100644
index 0000000..48b254b
--- /dev/null
+++ b/images/grpc-server/pom.xml
@@ -0,0 +1,61 @@
+
+
+
+ 4.0.0
+ pom
+
+ cicd.images.grpc-server
+ com.seemscloud.cicd.images.grpc-server
+
+
+ cicd.images
+ com.seemscloud.cicd.images
+ 1.4.2-SNAPSHOT
+
+
+
+
+
+ io.fabric8
+ docker-maven-plugin
+
+ true
+
+
+ grpc-server
+ seemscloud/grpc-server:latest
+
+ ${project.basedir}
+ @
+
+
+
+ grpc-server
+ seemscloud/grpc-server:${project.version}
+
+ ${project.basedir}
+ @
+
+
+
+
+
+
+ build docker
+ package
+
+ build
+
+
+
+ push docker
+ deploy
+
+ push
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/images/grpc-server/src/README.md b/images/grpc-server/src/README.md
new file mode 100644
index 0000000..e275399
--- /dev/null
+++ b/images/grpc-server/src/README.md
@@ -0,0 +1,6 @@
+```bash
+export LISTEN_PORT="9000"
+export LISTEN_PORT_TLS="9443"
+
+python3 server.py
+```
\ No newline at end of file
diff --git a/images/grpc-server/src/health.proto b/images/grpc-server/src/health.proto
new file mode 100644
index 0000000..c92ddc2
--- /dev/null
+++ b/images/grpc-server/src/health.proto
@@ -0,0 +1,29 @@
+syntax = "proto3";
+
+package grpc.health.v1;
+
+option csharp_namespace = "Grpc.Health.V1";
+option go_package = "google.golang.org/grpc/health/grpc_health_v1";
+option java_multiple_files = true;
+option java_outer_classname = "HealthProto";
+option java_package = "io.grpc.health.v1";
+
+service Health {
+ rpc Check(HealthCheckRequest) returns (HealthCheckResponse);
+
+ rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse);
+}
+
+message HealthCheckRequest {
+ string service = 1;
+}
+
+message HealthCheckResponse {
+ enum ServingStatus {
+ UNKNOWN = 0;
+ SERVING = 1;
+ NOT_SERVING = 2;
+ SERVICE_UNKNOWN = 3;
+ }
+ ServingStatus status = 1;
+}
\ No newline at end of file
diff --git a/images/grpc-server/src/helloworld.proto b/images/grpc-server/src/helloworld.proto
new file mode 100644
index 0000000..119dc1e
--- /dev/null
+++ b/images/grpc-server/src/helloworld.proto
@@ -0,0 +1,17 @@
+syntax = "proto3";
+
+package helloworld;
+
+service Greeter {
+ rpc SayHello (HelloRequest) returns (HelloReply) {}
+}
+
+message HelloRequest {
+ string name = 1;
+ string message = 2;
+}
+
+message HelloReply {
+ string name = 1;
+ string message = 2;
+}
\ No newline at end of file
diff --git a/images/grpc-server/src/server.crt.pem b/images/grpc-server/src/server.crt.pem
new file mode 100644
index 0000000..62e7c2e
--- /dev/null
+++ b/images/grpc-server/src/server.crt.pem
@@ -0,0 +1,63 @@
+-----BEGIN CERTIFICATE-----
+MIIFRzCCAy8CFEaAWxlfu65Ozgdst00u8yDMXnY6MA0GCSqGSIb3DQEBCwUAMFUx
+CzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdNYXpvdmlhMQ8wDQYDVQQHDAZXYXJzYXcx
+FDASBgNVBAoMC1NlZW1zIENsb3VkMQ0wCwYDVQQLDARSb290MB4XDTIyMTIxOTIx
+MDQ0M1oXDTI0MTIxODIxMDQ0M1owazELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB01h
+em92aWExDzANBgNVBAcMBldhcnNhdzEUMBIGA1UECgwLU2VlbXMgQ2xvdWQxDTAL
+BgNVBAsMBFJvb3QxFDASBgNVBAMMC2dycGMtc2VydmVyMIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEAkCGCZoNVU7Ijp1nCWYYW45vTvF7gJX6DPKHXp7Lp
+gLJUWzoBB9tvcl/i/b4UaEsRnHY/eaC0LJR9z54XeSSlLguaphai0GXhUkXAmJXZ
+o7AmzJ/Se1Xsl9P9pUMWpwQtUIcyYkqPZc3+zUvJ7aHSLrhtvttialrdutnQodve
+hdP7StWK9dSQHzj2m5PAH3ime3tCzEJQpuTR2qgeXau1hqeKjrckum3VwEfvd7qZ
+n2DzDt9Om85KjZ5E7x2UVzCreE7NO8tkQoSwYTY632wjmzL215KWbZ5WN/qmYmuX
+aNn307wqCc7YxaNKKmkZQaPw7Z72JF6W3IVWFtdWBWvF44lZMuOpsOif3xfZjF4S
+QzDI+XKAjohU7jzCYnqaFGVva5eZf6u9ywRdukrGmkXjMtiv5/TdKfJLTHWgZOOO
+yD87hMhCvOQL0VQadutSn1a3Mm6cZXozFdX3VlLrx27LODNgW7uQPtz180dW/6R/
+9qSCP/2dOQczq4Gxwu8tqVmMwglMMd7B/TqP/SZJb+/1aRRu9HYmuTzKfCl38X35
+ABuFKTToxLgO3gohWU4Bi/FNO/Ce8IQo3OuCdVvc/zWR4dNw6DLvS+C1YzuwIsmE
+tCQP32G/9ICT/gjm1cfNot8SGls0JxdSG/Dnnk7H0W6oepZNfTKZmjlvD6RBXWix
+tHECAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAEL8ZIVxGlo1e6rv/7gI0F+x4/Zzs
+XoIlCmJiWTJ1xdFPCd1mWKBi5WvxBJj7ZHyICqe8uCTlpfn6G+k8HAu/Nr4tKtX0
+Q358SSQH3GC5QCbnr1g35LyMgUwVqhHrTO3ye1RGtUkYnS5Vm2Qj/jzZbEKsslyd
+8gCVxDqa/rx1iZfLfMuIn7aqzBdu9aF5fC487ag9vNRbDu1qTuAb6YelMt+glRNx
+hGS7LSZFQeSnkaI7hP3UFEJHmOrL0n56CR+6g8oB7Vg1vKW+u2UaROo9qmHRnHCP
+I9ZJkkcGpyJrQQUk0GikDWBuB/iTcOkWL3QEaWEGbsJqoI2bEWaHbpdXBxfRNCiY
+zRwdx6y2e1pQDoclKoPMozshkkEtcbcj4H0nX+lz/jKwsj2HP8ebr4qj9iXt+n/N
+LkbR8YfX9h2dIjFtX/yYZNenNq192bbwS8ZxNnXzUX13oYAepaJ3wO7zzOFxc7fE
+obRl646HwsAFMibuUwpy2n3/mld0wBKIqPzqhNBKTp15+QLWfN1Ove1dybrztx/X
+/aAajPIT2g2q5xKjIQVW7Ob+03ZRsx13vLrra/okpbZxikc0GiRsF13kFUjlqs6V
+mAt/jp2aqXbYqngTBsHv3bVo/UIbDWdx7AgaqhWGLno3LVRRncXAhYIxYN/HOgr9
+U20Cds7FKlk58wY=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFizCCA3OgAwIBAgIUKopXQejrND/MAJGQHsbVWmB0ViwwDQYJKoZIhvcNAQEL
+BQAwVTELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB01hem92aWExDzANBgNVBAcMBldh
+cnNhdzEUMBIGA1UECgwLU2VlbXMgQ2xvdWQxDTALBgNVBAsMBFJvb3QwHhcNMjIx
+MjE5MjAxMDU3WhcNMzIxMjE2MjAxMDU3WjBVMQswCQYDVQQGEwJVUzEQMA4GA1UE
+CAwHTWF6b3ZpYTEPMA0GA1UEBwwGV2Fyc2F3MRQwEgYDVQQKDAtTZWVtcyBDbG91
+ZDENMAsGA1UECwwEUm9vdDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
+AKhHHO6eb9Zk1B3MFUIg7ntUfs6l5TyPUi+vKn+/Jeu9eOmJX4skaHMGUh0fKF0z
+FSQwXRuqO1okxG/c6AHtBgf6afHC620i6Pv+kOLEzEa3rL1ij34bCAccHREGHuyO
+9u2T3IwacASZYdTvI6biXvRQq1x3zRCT+VWCuNoPbzet6GZ2h69IWgLZKFwLDdFU
+AGLcwS8E7oLabxEZ4X8W9V9aPmMJczAxfXSAgewx4G71Z1rdIQ6WD03fOIKNeeBo
+oJ+LGKbD9NYz7F6Gmw4ngPRYWqVUogi1qRuTOd7twOKw/PZzm0nf/g0o7m9ssQZM
+WmFVdbQlsY4w0RLWZYd7kCcyTleBTZDgZFSfc1ynMmCKQvKV4PZaNCprKGtRHn2L
+/80nY1NxQfgLN6w2aMW6y2Ps4wAp+LnBL1PtOUcGO2DQetK+7Y6a1ATnVH+zm4di
+NXKDsYomgLUMqcdT+cCrdqQwpAFzNihC3v7U8xopuIdfmCpIHYPlTxBDi2wmQ93K
+1XrEScMf7knAEgR7Ar5r0K4U79wx6SHc/Unxz/VzRI26Apnv3pIOi831zO4WScPg
+/ydskvZegTCHwBov+BlZEzFDiVj6CCbM6cKj7RoMUyCmrbDb2B6BN+NmRIkDLJht
+4eEhbLaF4sE8nQq0Xa9ZqI3rFJTfYC8kJrQPeQgf45v5AgMBAAGjUzBRMB0GA1Ud
+DgQWBBSNd8vAscwWdDR7AV8slr98YMd9xjAfBgNVHSMEGDAWgBSNd8vAscwWdDR7
+AV8slr98YMd9xjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQBy
+XOd7xcEw14hIqHYJOZ9Kw5L6OlTIZg9u1+snAcYKWi0hWPJFV/lC+oonl4MvrUYQ
+ZXdXxL2Po3p2uyxpPpyaV0Rle4Alrz9ViOQwmqvUWzft3mLvpIJYnRRwXa2d5xX7
+Rz2x/DDRwacI1ew6v+D3CHm1LzILJsHwuk89sstWix48inYb4jFdHqvmfaK4XxCK
+hg6w95jOKd3mBaOgciqkjROQDPQqjjFvJJvjWe5BWNFaiyG1zZMBNumstLni3t0R
+d1pqhuZ4wnSUrybDGr7esYeECdApnkn3ryHjLBMS684/lMRpoyTWXaGPK/MePhoo
+Y26SWssjtU0sw9opp069j5FwLEjLyovarNUY+i3H43aihhwJgWyrZT2dugdHEQp+
+FgJH9TXIXQxzur4xbUH50s13bHg8jYYGBwLruzvT4zOyRib7ZjvRZca/J9Pombca
+Co2tQwulncbVh4+p8Vt6a10NmAlLetpylvpG/bU81T7wkB7QKwK4kGji20CvyBN0
+UfSitl9xwdsDmN9SjDOoeSNOnIgaE3FUyYq4U6eZbuvyojllZQtE+iWJvfOffaI8
+Dvm9lU52+fzpPR3kf0kXCfaryacEieQzxu7xW4DdjMosaHc2BGwPrnAdMtiFKsIH
+LYlo25/dUfiI7D6ZnbXLTpypH1FYYFZBGoiIVKAK3w==
+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/images/grpc-server/src/server.key.pem b/images/grpc-server/src/server.key.pem
new file mode 100644
index 0000000..e9c088b
--- /dev/null
+++ b/images/grpc-server/src/server.key.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+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
+F1Diykeauz3Qxwu6p3e7xmw3LkDO
+-----END PRIVATE KEY-----
\ No newline at end of file
diff --git a/images/grpc-server/src/server.py b/images/grpc-server/src/server.py
new file mode 100644
index 0000000..6ad5aed
--- /dev/null
+++ b/images/grpc-server/src/server.py
@@ -0,0 +1,58 @@
+import os
+import threading
+from concurrent import futures
+
+import grpc
+import grpc.experimental
+from grpc_reflection.v1alpha import reflection
+
+protos, services = grpc.protos_and_services("helloworld.proto")
+
+
+class Greeter(services.GreeterServicer):
+ def __init__(self):
+ self.name = "Ipsum"
+ self.message = "Pong!"
+
+ def SayHello(self, request, context):
+ print("Received '{}' from '{}'".format(request.message, request.name)),
+ print("Sent '{}' as '{}'".format(self.message, self.name))
+ print()
+
+ return protos.HelloReply(name=self.name, message=self.message)
+
+
+if __name__ == "__main__":
+ server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
+
+ greater = Greeter()
+
+ services.add_GreeterServicer_to_server(greater, server)
+
+ SERVICE_NAMES = (
+ protos.DESCRIPTOR.services_by_name['Greeter'].full_name,
+ reflection.SERVICE_NAME,
+ )
+ reflection.enable_server_reflection(SERVICE_NAMES, server)
+
+ if 'LISTEN_PORT_TLS' in os.environ:
+ server_port_tls = "0.0.0.0:{}".format(os.environ["LISTEN_PORT_TLS"])
+
+ server_key_file = 'server.key.pem'
+ server_cert_file = 'server.crt.pem'
+
+ server_key = open(server_key_file).read()
+ server_cert = open(server_cert_file).read()
+
+ credentials = grpc.ssl_server_credentials([(
+ bytes(server_key, "UTF-8"),
+ bytes(server_cert, "UTF-8")
+ )])
+
+ server.add_secure_port(server_port_tls, credentials)
+
+ server_port = "0.0.0.0:{}".format(os.environ["LISTEN_PORT"])
+ server.add_insecure_port(server_port)
+
+ server.start()
+ server.wait_for_termination()
diff --git a/images/grpc-xds-server/Dockerfile b/images/grpc-xds-server/Dockerfile
new file mode 100644
index 0000000..d176031
--- /dev/null
+++ b/images/grpc-xds-server/Dockerfile
@@ -0,0 +1,27 @@
+FROM python:3.10-alpine
+
+ARG USER_HOME="/app"
+ARG USER_NAME="grpc"
+ARG USER_UID="1000"
+ARG GROUP_NAME="${USER_NAME}"
+ARG GROUP_UID="${USER_UID}"
+
+RUN addgroup -g "${GROUP_UID}" "${GROUP_NAME}" && \
+ adduser -G "${GROUP_NAME}" -s /bin/bash -u "${USER_UID}" -h "${USER_HOME}" "${USER_NAME}" -D
+
+RUN apk update && \
+ apk add bash
+
+SHELL ["/bin/bash", "-c"]
+
+COPY docker-entrypoint.sh /
+
+WORKDIR "${USER_HOME}"
+USER "${USER_NAME}"
+
+RUN python3 -m pip install --upgrade pip && \
+ python3 -m pip install --upgrade grpcio grpcio-tools grpcio-reflection grpcio-health-checking protobuf
+
+COPY src .
+
+ENTRYPOINT ["/bin/bash", "/docker-entrypoint.sh"]
\ No newline at end of file
diff --git a/images/grpc-xds-server/docker-entrypoint.sh b/images/grpc-xds-server/docker-entrypoint.sh
new file mode 100644
index 0000000..8811100
--- /dev/null
+++ b/images/grpc-xds-server/docker-entrypoint.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+CONF_COLORS="$CONF_COLORS"
+
+function logger_format() {
+ DATE=$(date +"%Y-%m-%d %H:%M:%S,%3N")
+
+ if [[ "${CONF_COLORS}" == "true" ]]; then
+ echo -e "${DATE} \e[${3}m${1}\e[m\t ${2}"
+ else
+ echo -e "${DATE} ${1}\t ${2}"
+ fi
+}
+
+function logger_msg() {
+ if [ "${2}" == "error" ]; then
+ logger_format "ERROR" "${1}" "91"
+ elif [ "${2}" == "success" ]; then
+ logger_format "SUCCESS" "${1}" "92"
+ elif [ "${2}" == "warning" ]; then
+ logger_format "WARNING" "${1}" "93"
+ elif [ "${2}" == "info" ]; then
+ logger_format "INFO" "${1}" "96"
+ else
+ logger_format "LOGGER" "Incorrect logger type: '${2}'.." "31" && exit 4
+ fi
+}
+
+function logger() {
+ [ "${#}" -lt 2 ] || [ "${#}" -gt 2 ] && exit 1
+
+ logger_msg "${2}" "${1}"
+}
+
+python3 -u server.py
diff --git a/images/grpc-xds-server/pom.xml b/images/grpc-xds-server/pom.xml
new file mode 100644
index 0000000..1f14af4
--- /dev/null
+++ b/images/grpc-xds-server/pom.xml
@@ -0,0 +1,61 @@
+
+
+
+ 4.0.0
+ pom
+
+ cicd.images.grpc-xds-server
+ com.seemscloud.cicd.images.grpc-xds-server
+
+
+ cicd.images
+ com.seemscloud.cicd.images
+ 1.4.2-SNAPSHOT
+
+
+
+
+
+ io.fabric8
+ docker-maven-plugin
+
+ true
+
+
+ grpc-xds-server
+ seemscloud/grpc-xds-server:latest
+
+ ${project.basedir}
+ @
+
+
+
+ grpc-xds-server
+ seemscloud/grpc-xds-server:${project.version}
+
+ ${project.basedir}
+ @
+
+
+
+
+
+
+ build docker
+ package
+
+ build
+
+
+
+ push docker
+ deploy
+
+ push
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/images/grpc-xds-server/src/helloworld_pb2.py b/images/grpc-xds-server/src/helloworld_pb2.py
new file mode 100644
index 0000000..f5b4f2d
--- /dev/null
+++ b/images/grpc-xds-server/src/helloworld_pb2.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: helloworld.proto
+"""Generated protocol buffer code."""
+from google.protobuf.internal import builder as _builder
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x10helloworld.proto\x12\nhelloworld\"\x1c\n\x0cHelloRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x1d\n\nHelloReply\x12\x0f\n\x07message\x18\x01 \x01(\t2I\n\x07Greeter\x12>\n\x08SayHello\x12\x18.helloworld.HelloRequest\x1a\x16.helloworld.HelloReply\"\x00\x42\x36\n\x1bio.grpc.examples.helloworldB\x0fHelloWorldProtoP\x01\xa2\x02\x03HLWb\x06proto3')
+
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'helloworld_pb2', globals())
+if _descriptor._USE_C_DESCRIPTORS == False:
+
+ DESCRIPTOR._options = None
+ DESCRIPTOR._serialized_options = b'\n\033io.grpc.examples.helloworldB\017HelloWorldProtoP\001\242\002\003HLW'
+ _HELLOREQUEST._serialized_start=32
+ _HELLOREQUEST._serialized_end=60
+ _HELLOREPLY._serialized_start=62
+ _HELLOREPLY._serialized_end=91
+ _GREETER._serialized_start=93
+ _GREETER._serialized_end=166
+# @@protoc_insertion_point(module_scope)
diff --git a/images/grpc-xds-server/src/helloworld_pb2_grpc.py b/images/grpc-xds-server/src/helloworld_pb2_grpc.py
new file mode 100644
index 0000000..47c1869
--- /dev/null
+++ b/images/grpc-xds-server/src/helloworld_pb2_grpc.py
@@ -0,0 +1,70 @@
+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+"""Client and server classes corresponding to protobuf-defined services."""
+import grpc
+
+import helloworld_pb2 as helloworld__pb2
+
+
+class GreeterStub(object):
+ """The greeting service definition.
+ """
+
+ def __init__(self, channel):
+ """Constructor.
+
+ Args:
+ channel: A grpc.Channel.
+ """
+ self.SayHello = channel.unary_unary(
+ '/helloworld.Greeter/SayHello',
+ request_serializer=helloworld__pb2.HelloRequest.SerializeToString,
+ response_deserializer=helloworld__pb2.HelloReply.FromString,
+ )
+
+
+class GreeterServicer(object):
+ """The greeting service definition.
+ """
+
+ def SayHello(self, request, context):
+ """Sends a greeting
+ """
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+
+def add_GreeterServicer_to_server(servicer, server):
+ rpc_method_handlers = {
+ 'SayHello': grpc.unary_unary_rpc_method_handler(
+ servicer.SayHello,
+ request_deserializer=helloworld__pb2.HelloRequest.FromString,
+ response_serializer=helloworld__pb2.HelloReply.SerializeToString,
+ ),
+ }
+ generic_handler = grpc.method_handlers_generic_handler(
+ 'helloworld.Greeter', rpc_method_handlers)
+ server.add_generic_rpc_handlers((generic_handler,))
+
+
+ # This class is part of an EXPERIMENTAL API.
+class Greeter(object):
+ """The greeting service definition.
+ """
+
+ @staticmethod
+ def SayHello(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/helloworld.Greeter/SayHello',
+ helloworld__pb2.HelloRequest.SerializeToString,
+ helloworld__pb2.HelloReply.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
diff --git a/images/grpc-xds-server/src/server.py b/images/grpc-xds-server/src/server.py
new file mode 100644
index 0000000..915633e
--- /dev/null
+++ b/images/grpc-xds-server/src/server.py
@@ -0,0 +1,111 @@
+import argparse
+from concurrent import futures
+import logging
+import socket
+
+import grpc
+from grpc_health.v1 import health
+from grpc_health.v1 import health_pb2
+from grpc_health.v1 import health_pb2_grpc
+from grpc_reflection.v1alpha import reflection
+import helloworld_pb2
+import helloworld_pb2_grpc
+
+_DESCRIPTION = "A general purpose phony server."
+
+_LISTEN_HOST = "0.0.0.0"
+
+_THREAD_POOL_SIZE = 256
+
+logger = logging.getLogger()
+console_handler = logging.StreamHandler()
+formatter = logging.Formatter(fmt='%(asctime)s: %(levelname)-8s %(message)s')
+console_handler.setFormatter(formatter)
+logger.addHandler(console_handler)
+
+
+class Greeter(helloworld_pb2_grpc.GreeterServicer):
+
+ def __init__(self, hostname: str):
+ self._hostname = hostname if hostname else socket.gethostname()
+
+ def SayHello(self, request: helloworld_pb2.HelloRequest,
+ context: grpc.ServicerContext) -> helloworld_pb2.HelloReply:
+ return helloworld_pb2.HelloReply(
+ message=f"Hello {request.name} from {self._hostname}!")
+
+
+def _configure_maintenance_server(server: grpc.Server,
+ maintenance_port: int) -> None:
+ listen_address = f"{_LISTEN_HOST}:{maintenance_port}"
+ server.add_insecure_port(listen_address)
+
+ health_servicer = health.HealthServicer(
+ experimental_non_blocking=True,
+ experimental_thread_pool=futures.ThreadPoolExecutor(
+ max_workers=_THREAD_POOL_SIZE))
+
+ services = tuple(
+ service.full_name
+ for service in helloworld_pb2.DESCRIPTOR.services_by_name.values()) + (
+ reflection.SERVICE_NAME, health.SERVICE_NAME)
+
+ health_pb2_grpc.add_HealthServicer_to_server(health_servicer, server)
+ for service in services:
+ health_servicer.set(service, health_pb2.HealthCheckResponse.SERVING)
+ reflection.enable_server_reflection(services, server)
+
+
+def _configure_greeter_server(server: grpc.Server, port: int, secure_mode: bool,
+ hostname) -> None:
+ helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(hostname), server)
+ listen_address = f"{_LISTEN_HOST}:{port}"
+ if not secure_mode:
+ server.add_insecure_port(listen_address)
+ else:
+ logger.info("Running with xDS Server credentials")
+
+ server_fallback_creds = grpc.insecure_server_credentials()
+ server_creds = grpc.xds_server_credentials(server_fallback_creds)
+ server.add_secure_port(listen_address, server_creds)
+
+
+def serve(port: int, hostname: str, maintenance_port: int,
+ secure_mode: bool) -> None:
+ if port == maintenance_port:
+ server = grpc.server(futures.ThreadPoolExecutor(max_workers=_THREAD_POOL_SIZE))
+ _configure_greeter_server(server, port, secure_mode, hostname)
+ _configure_maintenance_server(server, maintenance_port)
+ server.start()
+ logger.info("Greeter server listening on port %d", port)
+ logger.info("Maintenance server listening on port %d", maintenance_port)
+ server.wait_for_termination()
+ else:
+ greeter_server = grpc.server(
+ futures.ThreadPoolExecutor(max_workers=_THREAD_POOL_SIZE), xds=secure_mode)
+ _configure_greeter_server(greeter_server, port, secure_mode, hostname)
+ greeter_server.start()
+ logger.info("Greeter server listening on port %d", port)
+ maintenance_server = grpc.server(futures.ThreadPoolExecutor(max_workers=_THREAD_POOL_SIZE))
+ _configure_maintenance_server(maintenance_server, maintenance_port)
+ maintenance_server.start()
+ logger.info("Maintenance server listening on port %d", maintenance_port)
+ greeter_server.wait_for_termination()
+ maintenance_server.wait_for_termination()
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description=_DESCRIPTION)
+ parser.add_argument("port", default=50051, type=int, nargs="?",
+ help="The port on which to listen.")
+
+ parser.add_argument("hostname", type=str, default=None, nargs="?",
+ help="The name clients will see in responses.")
+
+ parser.add_argument("--xds-creds", action="store_true",
+ help="If specified, uses xDS credentials to connect to the server.")
+
+ args = parser.parse_args()
+ logging.basicConfig()
+ logger.setLevel(logging.INFO)
+ serve(args.port, args.hostname, args.port + 1, args.xds_creds)
diff --git a/images/k3s/Dockerfile b/images/k3s/Dockerfile
new file mode 100644
index 0000000..574ea5b
--- /dev/null
+++ b/images/k3s/Dockerfile
@@ -0,0 +1,28 @@
+FROM alpine:3.18.4
+
+RUN rm -rf /bin
+COPY --from=rancher/k3s:v1.27.4-k3s1 /bin /bin
+
+RUN set -ex; \
+ apk add --no-cache iptables ip6tables nfs-utils rpcbind openrc bash; \
+ echo 'hosts: files dns' > /etc/nsswitch.conf
+
+RUN rc-update add rpcbind && \
+ rc-update add nfs
+
+RUN mkdir -p /run/openrc && \
+ touch /run/openrc/softlevel
+
+VOLUME /var/lib/kubelet
+VOLUME /var/lib/rancher/k3s
+VOLUME /var/lib/cni
+VOLUME /var/log
+
+ENV PATH="${PATH}:/bin/aux"
+ENV CRI_CONFIG_FILE="/var/lib/rancher/k3s/agent/etc/crictl.yaml"
+
+COPY k3d-entrypoint-nfs.sh /bin
+RUN chmod +x /bin/k3d-entrypoint-nfs.sh
+
+ENTRYPOINT ["/bin/k3d-entrypoint-nfs.sh"]
+CMD ["agent"]
\ No newline at end of file
diff --git a/images/k3s/k3d-entrypoint-nfs.sh b/images/k3s/k3d-entrypoint-nfs.sh
new file mode 100644
index 0000000..a7c067d
--- /dev/null
+++ b/images/k3s/k3d-entrypoint-nfs.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+set -o errexit
+set -o nounset
+set -o pipefail
+
+( sleep 10 && \
+ #/bin/rc-status > /tmp/rcstatus.moises && cat /tmp/rcstatus.moises && \
+ /bin/rc-status ) &
+
+( sleep 20 && \
+ touch /run/openrc/softlevel && \
+ /sbin/rc-service nfs start ) &
+
+exec /bin/k3s "$@"
\ No newline at end of file
diff --git a/images/k3s/pom.xml b/images/k3s/pom.xml
new file mode 100644
index 0000000..f599ab9
--- /dev/null
+++ b/images/k3s/pom.xml
@@ -0,0 +1,61 @@
+
+
+
+ 4.0.0
+ pom
+
+ cicd.images.k3s
+ com.seemscloud.cicd.images.k3s
+
+
+ cicd.images
+ com.seemscloud.cicd.images
+ 1.4.2-SNAPSHOT
+
+
+
+
+
+ io.fabric8
+ docker-maven-plugin
+
+ true
+
+
+ debug
+ seemscloud/debug:latest
+
+ ${project.basedir}
+ @
+
+
+
+ debug
+ seemscloud/debug:${project.version}
+
+ ${project.basedir}
+ @
+
+
+
+
+
+
+ build docker
+ package
+
+ build
+
+
+
+ push docker
+ deploy
+
+ push
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/images/pom.xml b/images/pom.xml
new file mode 100644
index 0000000..ee66374
--- /dev/null
+++ b/images/pom.xml
@@ -0,0 +1,42 @@
+
+
+
+ 4.0.0
+ pom
+
+ cicd.images
+ com.seemscloud.cicd.images
+
+
+ cicd
+ com.seemscloud.cicd
+ 1.4.2-SNAPSHOT
+
+
+
+ debug
+ fastapi
+ grpc-client
+ grpc-server
+ grpc-xds-server
+ k3s
+
+
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+ 3.4.0
+
+
+ parse-version
+
+ parse-version
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..5877d9d
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,97 @@
+
+
+
+ 4.0.0
+ pom
+
+ cicd
+ com.seemscloud.cicd
+ 1.4.2-SNAPSHOT
+
+
+ https://github.com/seemscloud/github-actions-maven-cicd
+ scm:git:https://github.com/seemscloud/github-actions-maven-cicd.git
+ scm:git:https://github.com/seemscloud/github-actions-maven-cicd.git
+
+
+ main
+
+
+
+ images
+
+
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+ 3.4.0
+
+
+ parse-version
+
+ parse-version
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-release-plugin
+
+
+ pom.xml
+
+
+
+
+ org.apache.maven.plugins
+ maven-release-plugin
+ 3.0.1
+
+
+ org.apache.maven.plugins
+ maven-release-plugin
+ 3.0.0
+
+
+ nl.basjes.maven.release
+ conventional-commits-version-policy
+ 1.0.4
+
+
+
+ [Versioner] Version @{releaseLabel}
+ [Versioner] Bump Patch version
+ [Versioner] Rollback the release of @{releaseLabel}
+
+
+ @{project.version}
+ true
+ true
+
+ ConventionalCommitsVersionPolicy
+
+ ^([0-9]+\.[0-9]+\.[0-9]+)$
+
+ ^feat: .*$
+
+
+
+
+
+ prepare-release
+ install
+
+ prepare
+
+
+ true
+
+
+
+
+
+
+
\ No newline at end of file