Skip to content
This repository has been archived by the owner on Jul 9, 2024. It is now read-only.

vaccipy als docker container #375

Open
funnym0nk3y opened this issue Jun 8, 2021 · 10 comments
Open

vaccipy als docker container #375

funnym0nk3y opened this issue Jun 8, 2021 · 10 comments
Labels
enhancement New feature or request

Comments

@funnym0nk3y
Copy link

Hey,

es wäre cool, wenn es vaccipy auch als docker container geben würde.

@timreibe timreibe added the enhancement New feature or request label Jun 8, 2021
@marvin-te
Copy link

wird glaube ich schwierig. Ich habs lokal gemacht und konnte den Termin nicht buchen, da vaccipy Chrome nicht starten konnte. Sehr ärgerlich.

@funnym0nk3y
Copy link
Author

funnym0nk3y commented Jun 8, 2021

Darf ich fragen, wie genau du das gemacht hast? @marvin-te
Ich hab das Programm leider noch nicht genau verstanden und weiß deshalb nicht, ob der Prozess komplett headless möglich ist, bzw warum manche Sachen headless gemacht werden und manche nicht. Prinzipiell könnte man ja chromium in den container mit rein packen...

@marvin-te
Copy link

In meiner Frage gestern #361 wurde mir bestätigt, dass für die Buchung des Termins eine GUI notwendig ist. Mir ist kein Weg bekannt, eine GUI Application in einem Docker Container laufen zu lassen.

@marvin-te
Copy link

Daher ist es, denke ich, nicht sinnvoll möglich, vaccipy in einem Docker Container laufen zu lassen.
Mein Ansatz war bisher halt eine Dockerfile mit python als base, in der ich das repo gecloned habe und eine json mit entsprechenden Kontaktdaten kopiert habe.
Lief super, bis zur Buchung. Die funktionierte nicht.

@funnym0nk3y
Copy link
Author

funnym0nk3y commented Jun 8, 2021

Die habe ich leider nicht gesehen, danke für den Hinweis. Ist es denn prinzipiell möglich, valide Cookies headless zu generieren oder ist das eine Sache der Implementierung?

Also wenn ich das richtig verstanden habe braucht man für valide Cookies die Mausbewegungen und Klicks.

@sinun98
Copy link
Collaborator

sinun98 commented Jun 8, 2021

Die habe ich leider nicht gesehen, danke für den Hinweis. Ist es denn prinzipiell möglich, valide Cookies headless zu generieren oder ist das eine Sache der Implementierung?

Also wenn ich das richtig verstanden habe braucht man für valide Cookies die Mausbewegungen und Klicks.

Wenn du es headless hinbekommst wäre klasse. Wir haben es leider nicht geschafft. Die Cookies werden immer geblockt.

@s-hamann
Copy link

s-hamann commented Jun 9, 2021

Mir ist kein Weg bekannt, eine GUI Application in einem Docker Container laufen zu lassen.

Es ist durchaus möglich, GUI-Anwendungen in einem Container laufen zu lassen, allerdings nicht ganz intutiv. Mit Chrome/Chromium habe ich das nicht probiert, aber generell sieht der Aufruf (ganz grob) so aus:

args=()
# 1. export xauth cookie to the container
xauth_file='/tmp/container.xauth'
touch -- "${xauth_file}"
xauth nextract - "${DISPLAY}" | sed -e '/^..../ffff/' | xauth -f "${xauth_file}"
args+=( "--volume=${xauth_file}:/home/.../.Xauthority:ro" )
# 2. export X11 display information
args+=( "--env=DISPLAY=unix${DISPLAY}" "--volume=/tmp/.x11-unix:/tmp/.x11-unix:ro" )
# 3. export Wayland display information
args+=( "--env=WAYLAND_DISPLAY" "--env=XDG_RUNTIME_DIR" "--volume=${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}:${XDG_RUNTIME_DIR}/${WAYLAND_DISPLAY}" )
# run it
podman run --rm -it "${args[@]}" vaccipy

Falls auf dem Host X11 läuft kann man Schritt 3 weg lassen; falls Wayland läuft, dann ist Schritt 1 nicht nötig.

Getestet habe ich das nur mit Podman, sollte aber mit Docker ganz genauso funktionieren.

Möglicherweise müssen für Chrome/Chromium noch Einträge aus /dev/ exportiert werden.

@apeltzer
Copy link
Contributor

apeltzer commented Jun 9, 2021

Podman macht vieles einfacher als Docker, ähnlich wie Singularity - was bei Docker immer ein gebastel war um X11 rauszubekommen ging z.B. bei mir mit Singularity "einfach so". Gehen tuts, aber "schön" ist es nicht.

@dnlfrst
Copy link

dnlfrst commented Jun 10, 2021

Ich habe gerade gesehen, dass auf #418 keine positive Resonanz folgte, gerne kann meine PR (#424) daher kommentarlos geschlossen werden.


Problemstellung

Das hier beschriebene Problem ist bereits vielfach hervorragend gelöst worden, u.a. für UI Tests in Docker. Eine solche Lösung bietet auch Selenium, deren Bibliothek bereits in vaccipy verwendet wird, selbst an. Da auch ich an einem Deployment von vaccipy in Docker interessiert bin, habe ich die nachfolgende Lösung in meinem Fork implementiert.

Lösungsvorschlag

Selenium bietet die gängigen Browser wie Google Chrome als Docker Image auf Docker Hub an. Passend dazu, kann in selenium per Remote eine Verbindung zu der Instanz dieses Browsers aufgebaut werden.

Diese Funktionen sind out-of-the-box verfügbar und können in Docker Compose wie folgt kombiniert werden:

version: "3.9"
services:
  google-chrome:
    environment:
      # Necessary to allow connections other than from the local address.
      - JAVA_OPTS=-Dwebdriver.chrome.whitelistedIps=
    image: selenium/standalone-chrome:91.0
    ports:
      - "4444:4444"
  vaccipy:
    build: .
    # Arguments passed to vaccipy.
    command: ${VACCIPY_ARGUMENTS}
    environment:
      - VACCIPY_CHROME_REMOTE_ADDRESS=http://google-chrome:4444/wd/hub
    image: vaccipy
    volumes:
      - type: bind
        read_only: true
        source: ${VACCIPY_CONTACT_ADDRESS_PATH}
        target: /vaccipy/kontaktdaten.json

Der Service vaccipy basiert wiederum auf folgendem Dockerfile:

FROM python:3.9.5-buster

WORKDIR vaccipy

RUN apt-get update && apt-get install -y jq

ADD . .

RUN python -m pip install -r requirements.txt

RUN chmod +x ./wait-for-google-chrome.sh

ENTRYPOINT ./wait-for-google-chrome.sh python3 main.py search -f kontaktdaten.json -r

Da das Deployment nicht auf Interaktion ausgelegt ist, habe ich zwei neue Umgebungsvariablen eingeführt: VACCIPY_ARGUMENTS und VACCIPY_CONTACT_ADDRESS_PATH. Erstere erlaubt zusätzlich Argumente für vaccipy zu definieren und zweitere ermöglicht, den Pfad einer bestehenden kontaktdaten.json festzulegen. Beide Werte sind standardmäßig durch .env festgelegt.

Mit dieser Implementation konnte ich erfolgreich einen Termin such und buchen:

Log aus Docker Compose
google-chrome_1  | 2021-06-10 11:57:10,901 INFO Included extra file "/etc/supervisor/conf.d/selenium.conf" during parsing
google-chrome_1  | 2021-06-10 11:57:10,906 INFO supervisord started with pid 7
vaccipy_1        | Waiting for Google Chrome to start...
google-chrome_1  | 2021-06-10 11:57:11,910 INFO spawned: 'xvfb' with pid 9
google-chrome_1  | 2021-06-10 11:57:11,914 INFO spawned: 'vnc' with pid 10
google-chrome_1  | 2021-06-10 11:57:11,916 INFO spawned: 'novnc' with pid 11
google-chrome_1  | 2021-06-10 11:57:11,920 INFO spawned: 'selenium-standalone' with pid 13
google-chrome_1  | 2021-06-10 11:57:11,963 INFO success: xvfb entered RUNNING state, process has stayed up for > than 0 seconds (startsecs)
google-chrome_1  | 2021-06-10 11:57:11,963 INFO success: vnc entered RUNNING state, process has stayed up for > than 0 seconds (startsecs)
google-chrome_1  | 2021-06-10 11:57:11,964 INFO success: novnc entered RUNNING state, process has stayed up for > than 0 seconds (startsecs)
google-chrome_1  | 2021-06-10 11:57:11,964 INFO success: selenium-standalone entered RUNNING state, process has stayed up for > than 0 seconds (startsecs)
google-chrome_1  | Selenium Grid Standalone configuration:
google-chrome_1  | [network]
google-chrome_1  | relax-checks = true
google-chrome_1  |
google-chrome_1  | [node]
google-chrome_1  | session-timeout = "300"
google-chrome_1  | override-max-sessions = false
google-chrome_1  | detect-drivers = false
google-chrome_1  | max-sessions = 1
google-chrome_1  |
google-chrome_1  | [[node.driver-configuration]]
google-chrome_1  | name = "chrome"
google-chrome_1  | stereotype = '{"browserName": "chrome", "browserVersion": "91.0", "platformName": "Linux"}'
google-chrome_1  | max-sessions = 1
google-chrome_1  |
google-chrome_1  | Starting Selenium Grid Standalone...
vaccipy_1        | Waiting for Google Chrome to start...
google-chrome_1  | 11:57:13.369 INFO [LoggingOptions.configureLogEncoding] - Using the system default encoding
google-chrome_1  | 11:57:13.377 INFO [OpenTelemetryTracer.createTracer] - Using OpenTelemetry for tracing
vaccipy_1        | Waiting for Google Chrome to start...
vaccipy_1        | Waiting for Google Chrome to start...
google-chrome_1  | 11:57:15.052 INFO [NodeOptions.getSessionFactories] - Detected 4 available processors
google-chrome_1  | 11:57:15.158 INFO [NodeOptions.report] - Adding chrome for {"browserName": "chrome","browserVersion": "91.0","platformName": "Linux"} 1 times
google-chrome_1  | 11:57:15.188 INFO [Node.<init>] - Binding additional locator mechanisms: id, name
google-chrome_1  | 11:57:15.206 INFO [LocalDistributor.add] - Added node ffa8debb-f0cb-4d00-bb1a-bb754e71b524 at http://172.19.0.2:4444.
google-chrome_1  | 11:57:15.250 INFO [GridModel.setAvailability] - Switching node ffa8debb-f0cb-4d00-bb1a-bb754e71b524 (uri: http://172.19.0.2:4444) from DOWN to UP
google-chrome_1  | 11:57:15.570 INFO [Standalone.execute] - Started Selenium Standalone 4.0.0-beta-4 (revision 29f46d02dd): http://172.19.0.2:4444
vaccipy_1        |
vaccipy_1        |                                 _
vaccipy_1        |                                (_)
vaccipy_1        |  __   __   __ _    ___    ___   _   _ __    _   _
vaccipy_1        |  \ \ / /  / _` |  / __|  / __| | | | '_ \  | | | |
vaccipy_1        |   \ V /  | (_| | | (__  | (__  | | | |_) | | |_| |
vaccipy_1        |    \_/    \__,_|  \___|  \___| |_| | .__/   \__, |
vaccipy_1        |                                    | |       __/ |
vaccipy_1        |                                    |_|      |___/
vaccipy_1        |
vaccipy_1        | vaccipy konnte nicht auf die neuste Version geprüft werden.
vaccipy_1        |
vaccipy_1        | Automatische Terminbuchung für den Corona Impfterminservice
vaccipy_1        |
vaccipy_1        | Vor der Ausführung des Programms ist die Berechtigung zur Impfung zu prüfen.
vaccipy_1        | Ob Anspruch auf eine Impfung besteht, kann hier nachgelesen werden:
vaccipy_1        | https://www.impfterminservice.de/terminservice/faq
vaccipy_1        |
vaccipy_1        | Kontaktdaten wurden geladen für: Daniel Fürst
vaccipy_1        |
vaccipy_1        | 2021-06-10 11:57:16.625   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   104 Impfzentren verfügbar
vaccipy_1        | 2021-06-10 11:57:16.625   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   'Landratsamt Schwarzwald-Baar-Kreis' in 78056 Villingen-Schwenningen ausgewählt
vaccipy_1        | 2021-06-10 11:57:16.625   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   'Kreisimpfzentrum Singen (Kreis Konstanz)' in 78224 Singen (Hohentwiel) ausgewählt
vaccipy_1        | 2021-06-10 11:57:16.625   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   'Kreisimpfzentrum Landkreis Tuttlingen' in 78532 Tuttlingen ausgewählt
vaccipy_1        | 2021-06-10 11:57:16.625   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   'Kreisimpfzentrum Rottweil, Stadthalle' in 78628 Rottweil ausgewählt
vaccipy_1        | 2021-06-10 11:57:16.668   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   [L920] Altersgruppe: 16+ (Intervall: 40 Tage) --> ['BioNTech']
vaccipy_1        | 2021-06-10 11:57:16.668   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   [L921] Altersgruppe: 18+ (Intervall: 40 Tage) --> ['Moderna', 'BioNTech']
vaccipy_1        | 2021-06-10 11:57:16.668   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   [L922] Altersgruppe: 60+ (Intervall: 40 Tage) --> ['Moderna', 'BioNTech', 'AstraZeneca']
vaccipy_1        | 2021-06-10 11:57:16.668   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   [L923] Altersgruppe: 60+ (Intervall:  ? Tage) --> ['Johnson&Johnson']
vaccipy_1        |
vaccipy_1        | 2021-06-10 11:57:16.668   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Browser-Cookies generieren
google-chrome_1  | 11:57:16.878 INFO [LocalDistributor.newSession] - Session request received by the distributor:
google-chrome_1  |  [Capabilities {browserName: chrome, goog:chromeOptions: {args: [disable-infobars, -disable-dev-shm-usage, user-agent=Mozilla/5.0, --headless], excludeSwitches: [enable-logging], extensions: []}, platform: ANY, version: }, Capabilities {browserName: chr
ome, goog:chromeOptions: {args: [disable-infobars, -disable-dev-shm-usage, user-agent=Mozilla/5.0, --headless], excludeSwitches: [enable-logging], extensions: []}}, Capabilities {browserName: chrome, goog:chromeOptions: {args: [disable-infobars, -disable-dev-shm-usage, us
er-agent=Mozilla/5.0, --headless], excludeSwitches: [enable-logging], extensions: []}, platformName: any}]
google-chrome_1  | Starting ChromeDriver 91.0.4472.19 (1bf021f248676a0b2ab3ee0561d83a59e424c23e-refs/branch-heads/4472@{#288}) on port 10236
google-chrome_1  | All remote connections are allowed. Use an allowlist instead!
google-chrome_1  | Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe.
google-chrome_1  | ChromeDriver was started successfully.
google-chrome_1  | 11:57:18.239 INFO [ProtocolHandshake.createSession] - Detected dialect: W3C
google-chrome_1  | 11:57:18.262 INFO [LocalDistributor.newSession] - Session created by the distributor. Id: 2579a3fb43c9a338fcb5805079ef0b53, Caps: Capabilities {acceptInsecureCerts: false, browserName: chrome, browserVersion: 91.0.4472.77, chrome: {chromedriverVersion:
91.0.4472.19 (1bf021f248676..., userDataDir: /tmp/.com.google.Chrome.WopHX6}, goog:chromeOptions: {debuggerAddress: localhost:41173}, networkConnectionEnabled: false, pageLoadStrategy: normal, platformName: ANY, proxy: Proxy(), se:cdp: ws://172.19.0.2:4444/sessio..., se:c
dpVersion: 91.0.4472.77, setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify, webauthn:extension:largeBlob: true, webauthn:virtualAuthenticators: true}
vaccipy_1        | 2021-06-10 11:57:18.270   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Code eintragen und Mausbewegung / Klicks simulieren. Dieser Vorgang kann einige Sekunden dauern.
vaccipy_1        | 2021-06-10 11:57:19.207   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
google-chrome_1  | 11:57:30.189 WARN [SeleniumSpanExporter$1.lambda$export$0] - {"traceId": "ea068daae5223cf93451a4f746ccd701","eventTime": 1623326250187724571,"eventName": "HTTP request execution complete","attributes": {"http.flavor": 1,"http.handler_class": "org.openqa
.selenium.remote.http.Route$PredicatedRoute","http.host": "172.19.0.2:4444","http.method": "POST","http.request_content_length": "730","http.scheme": "HTTP","http.status_code": 500,"http.target": "\u002fsession\u002f2579a3fb43c9a338fcb5805079ef0b53\u002factions","http.use
r_agent": "selenium\u002f3.141.0 (python linux)"}}
google-chrome_1  |
google-chrome_1  | 11:57:30.740 WARN [SeleniumSpanExporter$1.lambda$export$0] - {"traceId": "f1e51ad90b823e8eced282e1d75bc4bb","eventTime": 1623326250739293350,"eventName": "HTTP request execution complete","attributes": {"http.flavor": 1,"http.handler_class": "org.openqa
.selenium.remote.http.Route$PredicatedRoute","http.host": "172.19.0.2:4444","http.method": "POST","http.request_content_length": "845","http.scheme": "HTTP","http.status_code": 500,"http.target": "\u002fsession\u002f2579a3fb43c9a338fcb5805079ef0b53\u002factions","http.use
r_agent": "selenium\u002f3.141.0 (python linux)"}}
google-chrome_1  |
vaccipy_1        | 2021-06-10 11:57:30.866   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Browser-Cookie generiert: *sW+w==
google-chrome_1  | 11:57:30.972 INFO [LocalSessionMap.lambda$new$0] - Deleted session from local session map, Id: 2579a3fb43c9a338fcb5805079ef0b53
vaccipy_1        | 2021-06-10 11:57:31.178   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Keine Termine verfügbar in 78056
vaccipy_1        | 2021-06-10 11:58:01.337   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Keine Termine verfügbar in 78224
vaccipy_1        | 2021-06-10 11:58:31.508   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Keine Termine verfügbar in 78532
vaccipy_1        | 2021-06-10 11:59:01.727   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Keine Termine verfügbar in 78628
vaccipy_1        | 2021-06-10 13:19:45.827   impfterminservice   [err] [termin_suchen]   Timeout exception raised
vaccipy_1        | 2021-06-10 13:19:45.828   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Browser-Cookies generieren
google-chrome_1  | 13:19:45.857 INFO [LocalDistributor.newSession] - Session request received by the distributor:
google-chrome_1  |  [Capabilities {browserName: chrome, goog:chromeOptions: {args: [disable-infobars, -disable-dev-shm-usage, user-agent=Mozilla/5.0, --headless], excludeSwitches: [enable-logging], extensions: []}, platform: ANY, version: }, Capabilities {browserName: chr
ome, goog:chromeOptions: {args: [disable-infobars, -disable-dev-shm-usage, user-agent=Mozilla/5.0, --headless], excludeSwitches: [enable-logging], extensions: []}}, Capabilities {browserName: chrome, goog:chromeOptions: {args: [disable-infobars, -disable-dev-shm-usage, us
er-agent=Mozilla/5.0, --headless], excludeSwitches: [enable-logging], extensions: []}, platformName: any}]
google-chrome_1  | Starting ChromeDriver 91.0.4472.19 (1bf021f248676a0b2ab3ee0561d83a59e424c23e-refs/branch-heads/4472@{#288}) on port 30790
google-chrome_1  | All remote connections are allowed. Use an allowlist instead!
google-chrome_1  | Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe.
google-chrome_1  | ChromeDriver was started successfully.
google-chrome_1  | 13:19:46.290 INFO [ProtocolHandshake.createSession] - Detected dialect: W3C
google-chrome_1  | 13:19:46.301 INFO [LocalDistributor.newSession] - Session created by the distributor. Id: 2f3c4265da24946bf5d700d864b36aab, Caps: Capabilities {acceptInsecureCerts: false, browserName: chrome, browserVersion: 91.0.4472.77, chrome: {chromedriverVersion:
91.0.4472.19 (1bf021f248676..., userDataDir: /tmp/.com.google.Chrome.rFv1e9}, goog:chromeOptions: {debuggerAddress: localhost:35815}, networkConnectionEnabled: false, pageLoadStrategy: normal, platformName: ANY, proxy: Proxy(), se:cdp: ws://172.19.0.2:4444/sessio..., se:c
dpVersion: 91.0.4472.77, setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify, webauthn:extension:largeBlob: true, webauthn:virtualAuthenticators: true}
vaccipy_1        | 2021-06-10 13:19:46.355   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Code eintragen und Mausbewegung / Klicks simulieren. Dieser Vorgang kann einige Sekunden dauern.
google-chrome_1  | 13:19:47.214 WARN [SeleniumSpanExporter$1.lambda$export$0] - {"traceId": "45e83025ea5add1e9f5797bd2f6331e7","eventTime": 1623331187213014033,"eventName": "HTTP request execution complete","attributes": {"http.flavor": 1,"http.handler_class": "org.openqa
.selenium.remote.http.Route$PredicatedRoute","http.host": "172.19.0.2:4444","http.method": "GET","http.scheme": "HTTP","http.status_code": 404,"http.target": "\u002fsession\u002f2f3c4265da24946bf5d700d864b36aab\u002fcookie\u002fakavpwr_User_allowed","http.user_agent": "se
lenium\u002f3.141.0 (python linux)"}}
google-chrome_1  |
google-chrome_1  | 13:19:53.757 WARN [SeleniumSpanExporter$1.lambda$export$0] - {"traceId": "271dd485eab841c3d1f6c7637636f709","eventTime": 1623331193755937859,"eventName": "HTTP request execution complete","attributes": {"http.flavor": 1,"http.handler_class": "org.openqa
.selenium.remote.http.Route$PredicatedRoute","http.host": "172.19.0.2:4444","http.method": "POST","http.request_content_length": "730","http.scheme": "HTTP","http.status_code": 500,"http.target": "\u002fsession\u002f2f3c4265da24946bf5d700d864b36aab\u002factions","http.use
r_agent": "selenium\u002f3.141.0 (python linux)"}}
google-chrome_1  |
google-chrome_1  | 13:19:54.307 WARN [SeleniumSpanExporter$1.lambda$export$0] - {"traceId": "3847accbf0ec9137288b4e2bdef30ccf","eventTime": 1623331194306129347,"eventName": "HTTP request execution complete","attributes": {"http.flavor": 1,"http.handler_class": "org.openqa
.selenium.remote.http.Route$PredicatedRoute","http.host": "172.19.0.2:4444","http.method": "POST","http.request_content_length": "845","http.scheme": "HTTP","http.status_code": 500,"http.target": "\u002fsession\u002f2f3c4265da24946bf5d700d864b36aab\u002factions","http.use
r_agent": "selenium\u002f3.141.0 (python linux)"}}
google-chrome_1  |
vaccipy_1        | 2021-06-10 13:19:54.339   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Browser-Cookie generiert: *+lCw==
google-chrome_1  | 13:19:54.453 INFO [LocalSessionMap.lambda$new$0] - Deleted session from local session map, Id: 2f3c4265da24946bf5d700d864b36aab
vaccipy_1        | 2021-06-10 13:20:09.505   impfterminservice   [err] [termin_suchen]   Timeout exception raised
vaccipy_1        | 2021-06-10 13:20:09.506   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Browser-Cookies generieren
google-chrome_1  | 13:20:09.518 INFO [LocalDistributor.newSession] - Session request received by the distributor:
google-chrome_1  |  [Capabilities {browserName: chrome, goog:chromeOptions: {args: [disable-infobars, -disable-dev-shm-usage, user-agent=Mozilla/5.0, --headless], excludeSwitches: [enable-logging], extensions: []}, platform: ANY, version: }, Capabilities {browserName: chr
ome, goog:chromeOptions: {args: [disable-infobars, -disable-dev-shm-usage, user-agent=Mozilla/5.0, --headless], excludeSwitches: [enable-logging], extensions: []}}, Capabilities {browserName: chrome, goog:chromeOptions: {args: [disable-infobars, -disable-dev-shm-usage, us
er-agent=Mozilla/5.0, --headless], excludeSwitches: [enable-logging], extensions: []}, platformName: any}]
google-chrome_1  | Starting ChromeDriver 91.0.4472.19 (1bf021f248676a0b2ab3ee0561d83a59e424c23e-refs/branch-heads/4472@{#288}) on port 1495
google-chrome_1  | All remote connections are allowed. Use an allowlist instead!
google-chrome_1  | Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe.
google-chrome_1  | ChromeDriver was started successfully.
google-chrome_1  | 13:20:09.857 INFO [ProtocolHandshake.createSession] - Detected dialect: W3C
google-chrome_1  | 13:20:09.862 INFO [LocalDistributor.newSession] - Session created by the distributor. Id: 95c6cea214786683f5be1741263c2954, Caps: Capabilities {acceptInsecureCerts: false, browserName: chrome, browserVersion: 91.0.4472.77, chrome: {chromedriverVersion:
91.0.4472.19 (1bf021f248676..., userDataDir: /tmp/.com.google.Chrome.67oGMj}, goog:chromeOptions: {debuggerAddress: localhost:45173}, networkConnectionEnabled: false, pageLoadStrategy: normal, platformName: ANY, proxy: Proxy(), se:cdp: ws://172.19.0.2:4444/sessio..., se:c
dpVersion: 91.0.4472.77, setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify, webauthn:extension:largeBlob: true, webauthn:virtualAuthenticators: true}
vaccipy_1        | 2021-06-10 13:20:09.870   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Code eintragen und Mausbewegung / Klicks simulieren. Dieser Vorgang kann einige Sekunden dauern.
google-chrome_1  | 13:20:10.904 WARN [SeleniumSpanExporter$1.lambda$export$0] - {"traceId": "c6e58e1528f73d9fd3dd4eddb2f6d4dd","eventTime": 1623331210903266429,"eventName": "HTTP request execution complete","attributes": {"http.flavor": 1,"http.handler_class": "org.openqa
.selenium.remote.http.Route$PredicatedRoute","http.host": "172.19.0.2:4444","http.method": "GET","http.scheme": "HTTP","http.status_code": 404,"http.target": "\u002fsession\u002f95c6cea214786683f5be1741263c2954\u002fcookie\u002fakavpwr_User_allowed","http.user_agent": "se
lenium\u002f3.141.0 (python linux)"}}
google-chrome_1  |
google-chrome_1  | 13:20:15.392 WARN [SeleniumSpanExporter$1.lambda$export$0] - {"traceId": "2dcb8d3e5cc9722b0a5e1ad73a7063c5","eventTime": 1623331215391879051,"eventName": "HTTP request execution complete","attributes": {"http.flavor": 1,"http.handler_class": "org.openqa
.selenium.remote.http.Route$PredicatedRoute","http.host": "172.19.0.2:4444","http.method": "POST","http.request_content_length": "730","http.scheme": "HTTP","http.status_code": 500,"http.target": "\u002fsession\u002f95c6cea214786683f5be1741263c2954\u002factions","http.use
r_agent": "selenium\u002f3.141.0 (python linux)"}}
google-chrome_1  |
google-chrome_1  | 13:20:16.194 WARN [SeleniumSpanExporter$1.lambda$export$0] - {"traceId": "edc7b36e2595bf694a42e3660db38d14","eventTime": 1623331216193083563,"eventName": "HTTP request execution complete","attributes": {"http.flavor": 1,"http.handler_class": "org.openqa
.selenium.remote.http.Route$PredicatedRoute","http.host": "172.19.0.2:4444","http.method": "POST","http.request_content_length": "845","http.scheme": "HTTP","http.status_code": 500,"http.target": "\u002fsession\u002f95c6cea214786683f5be1741263c2954\u002factions","http.use
r_agent": "selenium\u002f3.141.0 (python linux)"}}
google-chrome_1  |
vaccipy_1        | 2021-06-10 13:20:16.236   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Browser-Cookie generiert: *dn+Q==
google-chrome_1  | 13:20:16.310 INFO [LocalSessionMap.lambda$new$0] - Deleted session from local session map, Id: 95c6cea214786683f5be1741263c2954
vaccipy_1        | 2021-06-10 13:20:31.367   impfterminservice   [err] [termin_suchen]   Timeout exception raised
vaccipy_1        | 2021-06-10 13:20:31.368   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Browser-Cookies generieren
google-chrome_1  | 13:20:31.387 INFO [LocalDistributor.newSession] - Session request received by the distributor:
google-chrome_1  |  [Capabilities {browserName: chrome, goog:chromeOptions: {args: [disable-infobars, -disable-dev-shm-usage, user-agent=Mozilla/5.0, --headless], excludeSwitches: [enable-logging], extensions: []}, platform: ANY, version: }, Capabilities {browserName: chr
ome, goog:chromeOptions: {args: [disable-infobars, -disable-dev-shm-usage, user-agent=Mozilla/5.0, --headless], excludeSwitches: [enable-logging], extensions: []}}, Capabilities {browserName: chrome, goog:chromeOptions: {args: [disable-infobars, -disable-dev-shm-usage, us
er-agent=Mozilla/5.0, --headless], excludeSwitches: [enable-logging], extensions: []}, platformName: any}]
google-chrome_1  | Starting ChromeDriver 91.0.4472.19 (1bf021f248676a0b2ab3ee0561d83a59e424c23e-refs/branch-heads/4472@{#288}) on port 6081
google-chrome_1  | All remote connections are allowed. Use an allowlist instead!
google-chrome_1  | Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe.
google-chrome_1  | ChromeDriver was started successfully.
google-chrome_1  | 13:20:31.753 INFO [ProtocolHandshake.createSession] - Detected dialect: W3C
google-chrome_1  | 13:20:31.759 INFO [LocalDistributor.newSession] - Session created by the distributor. Id: 1e64d70d4188e9c3cf4f46faa38b3e08, Caps: Capabilities {acceptInsecureCerts: false, browserName: chrome, browserVersion: 91.0.4472.77, chrome: {chromedriverVersion:
91.0.4472.19 (1bf021f248676..., userDataDir: /tmp/.com.google.Chrome.Y0qpOg}, goog:chromeOptions: {debuggerAddress: localhost:34377}, networkConnectionEnabled: false, pageLoadStrategy: normal, platformName: ANY, proxy: Proxy(), se:cdp: ws://172.19.0.2:4444/sessio..., se:c
dpVersion: 91.0.4472.77, setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify, webauthn:extension:largeBlob: true, webauthn:virtualAuthenticators: true}
vaccipy_1        | 2021-06-10 13:20:31.767   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Code eintragen und Mausbewegung / Klicks simulieren. Dieser Vorgang kann einige Sekunden dauern.
vaccipy_1        | 2021-06-10 13:20:32.110   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:20:37.457   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:20:42.606   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:20:47.857   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:20:53.059   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:20:58.285   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:21:03.498   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:21:08.703   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:21:13.912   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:21:19.100   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:21:24.293   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:21:29.515   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:21:34.710   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:21:39.899   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:21:45.081   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:21:50.253   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:21:55.458   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:22:00.675   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:22:05.910   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:22:11.161   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:22:16.355   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:22:21.505   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:22:26.765   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:22:31.904   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:22:37.114   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:22:42.362   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:22:47.511   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:22:52.753   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:22:57.965   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:23:03.176   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
vaccipy_1        | 2021-06-10 13:23:08.363   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Im Warteraum, Seite neu laden
google-chrome_1  | 13:23:20.795 WARN [SeleniumSpanExporter$1.lambda$export$0] - {"traceId": "c66803ff1c0d92f9a2a1d351bf98f6d2","eventTime": 1623331400794447585,"eventName": "HTTP request execution complete","attributes": {"http.flavor": 1,"http.handler_class": "org.openqa
.selenium.remote.http.Route$PredicatedRoute","http.host": "172.19.0.2:4444","http.method": "POST","http.request_content_length": "730","http.scheme": "HTTP","http.status_code": 500,"http.target": "\u002fsession\u002f1e64d70d4188e9c3cf4f46faa38b3e08\u002factions","http.use
r_agent": "selenium\u002f3.141.0 (python linux)"}}
google-chrome_1  |
vaccipy_1        | 2021-06-10 13:23:23.895   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Browser-Cookie generiert: *7Agw==
google-chrome_1  | 13:23:23.981 INFO [LocalSessionMap.lambda$new$0] - Deleted session from local session map, Id: 1e64d70d4188e9c3cf4f46faa38b3e08
vaccipy_1        | 2021-06-10 13:23:24.173   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Keine Termine verfügbar in 78628
vaccipy_1        | 2021-06-10 13:23:54.341   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Keine Termine verfügbar in 78056
vaccipy_1        | 2021-06-10 13:24:24.505   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Keine Termine verfügbar in 78224
vaccipy_1        | 2021-06-10 13:24:54.672   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Keine Termine verfügbar in 78532
vaccipy_1        | 2021-06-10 17:17:16.001   impfterminservice   [suc] [*G2SV | 78056, 78224, 78532, 78628]   Termin gefunden!
vaccipy_1        | 2021-06-10 17:17:16.001   impfterminservice   [suc] [*G2SV | 78056, 78224, 78532, 78628]   'Kreisimpfzentrum Rottweil, Stadthalle' in 78628 Rottweil
vaccipy_1        | 2021-06-10 17:17:16.002   impfterminservice   [suc] [*G2SV | 78056, 78224, 78532, 78628]   1. Termin: 14.06.2021 um 07:10 Uhr
vaccipy_1        | 2021-06-10 17:17:16.002   impfterminservice   [suc] [*G2SV | 78056, 78224, 78532, 78628]   2. Termin: 26.07.2021 um 05:50 Uhr
vaccipy_1        |
vaccipy_1        | 2021-06-10 17:17:16.064   impfterminservice   [err] [*G2SV | 78056, 78224, 78532, 78628]   Anfrage wurde von der Botprotection geblockt. Cookies werden erneuert und die Buchung wiederholt.
vaccipy_1        | 2021-06-10 17:17:16.065   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Browser-Cookies generieren
google-chrome_1  | 17:17:16.100 INFO [LocalDistributor.newSession] - Session request received by the distributor:
google-chrome_1  |  [Capabilities {browserName: chrome, goog:chromeOptions: {args: [-disable-dev-shm-usage, user-agent=Mozilla/5.0, disable-infobars], excludeSwitches: [enable-logging], extensions: []}}, Capabilities {browserName: chrome, goog:chromeOptions: {args: [-disa
ble-dev-shm-usage, user-agent=Mozilla/5.0, disable-infobars], excludeSwitches: [enable-logging], extensions: []}, platformName: any}, Capabilities {browserName: chrome, goog:chromeOptions: {args: [-disable-dev-shm-usage, user-agent=Mozilla/5.0, disable-infobars], excludeS
witches: [enable-logging], extensions: []}, platform: ANY, version: }]
google-chrome_1  | Starting ChromeDriver 91.0.4472.19 (1bf021f248676a0b2ab3ee0561d83a59e424c23e-refs/branch-heads/4472@{#288}) on port 2748
google-chrome_1  | All remote connections are allowed. Use an allowlist instead!
google-chrome_1  | Please see https://chromedriver.chromium.org/security-considerations for suggestions on keeping ChromeDriver safe.
google-chrome_1  | ChromeDriver was started successfully.
google-chrome_1  | 17:17:17.576 INFO [ProtocolHandshake.createSession] - Detected dialect: W3C
google-chrome_1  | 17:17:17.582 INFO [LocalDistributor.newSession] - Session created by the distributor. Id: 6e8cc8278ce62a5c779f2b8ee84e9a83, Caps: Capabilities {acceptInsecureCerts: false, browserName: chrome, browserVersion: 91.0.4472.77, chrome: {chromedriverVersion:
91.0.4472.19 (1bf021f248676..., userDataDir: /tmp/.com.google.Chrome.tDFOMN}, goog:chromeOptions: {debuggerAddress: localhost:42913}, networkConnectionEnabled: false, pageLoadStrategy: normal, platformName: linux, proxy: Proxy(), se:cdp: ws://172.19.0.2:4444/sessio..., se
:cdpVersion: 91.0.4472.77, setWindowRect: true, strictFileInteractability: false, timeouts: {implicit: 0, pageLoad: 300000, script: 30000}, unhandledPromptBehavior: dismiss and notify, webauthn:extension:largeBlob: true, webauthn:virtualAuthenticators: true}
vaccipy_1        | 2021-06-10 17:17:17.592   impfterminservice   [inf] [*G2SV | 78056, 78224, 78532, 78628]   Code eintragen und Mausbewegung / Klicks simulieren. Dieser Vorgang kann einige Sekunden dauern.
google-chrome_1  | 17:17:18.908 WARN [SeleniumSpanExporter$1.lambda$export$0] - {"traceId": "a9919d2482ae5b7eb54f565013b93a74","eventTime": 1623345438907140919,"eventName": "HTTP request execution complete","attributes": {"http.flavor": 1,"http.handler_class": "org.openqa
.selenium.remote.http.Route$PredicatedRoute","http.host": "172.19.0.2:4444","http.method": "GET","http.scheme": "HTTP","http.status_code": 404,"http.target": "\u002fsession\u002f6e8cc8278ce62a5c779f2b8ee84e9a83\u002fcookie\u002fakavpwr_User_allowed","http.user_agent": "se
lenium\u002f3.141.0 (python linux)"}}
google-chrome_1  |
google-chrome_1  | 17:17:23.210 WARN [SeleniumSpanExporter$1.lambda$export$0] - {"traceId": "90e9ccc5ac5a19a88477e353eb33cab8","eventTime": 1623345443209389434,"eventName": "HTTP request execution complete","attributes": {"http.flavor": 1,"http.handler_class": "org.openqa
.selenium.remote.http.Route$PredicatedRoute","http.host": "172.19.0.2:4444","http.method": "POST","http.request_content_length": "730","http.scheme": "HTTP","http.status_code": 404,"http.target": "\u002fsession\u002f6e8cc8278ce62a5c779f2b8ee84e9a83\u002factions","http.use
r_agent": "selenium\u002f3.141.0 (python linux)"}}
google-chrome_1  |
google-chrome_1  | 17:17:23.232 WARN [SeleniumSpanExporter$1.lambda$export$0] - {"traceId": "68dfa8e775fcd38fdd2a37fda73e574e","eventTime": 1623345443231879044,"eventName": "HTTP request execution complete","attributes": {"http.flavor": 1,"http.handler_class": "org.openqa
.selenium.remote.http.Route$PredicatedRoute","http.host": "172.19.0.2:4444","http.method": "POST","http.request_content_length": "845","http.scheme": "HTTP","http.status_code": 404,"http.target": "\u002fsession\u002f6e8cc8278ce62a5c779f2b8ee84e9a83\u002factions","http.use
r_agent": "selenium\u002f3.141.0 (python linux)"}}
google-chrome_1  |
google-chrome_1  | 17:17:23.346 INFO [LocalSessionMap.lambda$new$0] - Deleted session from local session map, Id: 6e8cc8278ce62a5c779f2b8ee84e9a83
vaccipy_1        | 2021-06-10 17:17:23.583   impfterminservice   [suc] [*G2SV | 78056, 78224, 78532, 78628]   Termin erfolgreich gebucht!
vaccipy_vaccipy_1 exited with code 0

Anmerkung: die obige Buchung erfolgte zu Testwecken und wurde umgehend storniert. Die angezeigten Uhrzeiten enstammen einer anderen Zeitzone und stimmen nicht mit UTC+0200 überein.

Einschränkungen

Automatisierung

Obgleich die obige Implementation technisch einwandfrei funktioniert, ermöglicht sie keine Automation der Terminbuchung. Es ist weiterhin notwendig, den Termin per Mail manuell zu bestätigen. Es entzieht sich dem Zweck von vaccipy diesen Schritt zu automatisieren. Insbesondere wird der Docker Container stoppen, sobald vaccipy erfolgreich einen Termin gebucht hat.

Sicherheit

Wie der Docker Compose Datei zu entnehmen, habe ich alle Verbindungen zur Instanz von Google Chrome zugelassen. Es ist daher denkbar, dass Dritte auf die Instanz von Google Chrome über den Docker Container zugreifen können. Standardmäßig lässt selenium/standalone-chrome bzw. Chromium nur Verbindungen von lokalen Adressen zu. Sollte Bedarf daran bestehen, den Vorschlag zu mergen, sollten wir versuchen, diese Whitelist einzuschränken, evtl. über den Namen des zugreifenden Containers, d.h. vaccipy.

Umgebungsvariablen

Es ist mir bisher nicht gelungen, die neu eingeführten Umgebungsvariablen über die Umgebung (hier tmux) zu definieren. Ich konnte die Werte lediglich über .env setzen.

Bemerkungen

  • Im Zuge venv der .gitignore hinzuzufügen, habe ich ein vollständiges, automatisch generiertes Template von gitignore.io eingesetzt.
  • Da bereits Umgebungsvariablen von der Software definiert werden, ist es der Konsistenz wegen eine sinnvolle Überlegung, alle Umgebungsvariablen in .env zusammenzuführen.

Ich möchte mich an dieser Stelle für das Engagement aller Beteiligten an dieser Software bedanken, sie löst ein reales Problem auf eine praktische Art & Weise. 👏🏼

@funnym0nk3y
Copy link
Author

funnym0nk3y commented Jun 12, 2021

@dnlfrst wirst du ein out-off-tree Dockerfile maintainen?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

7 participants