From f9e7df6af9b79a91afa48201a6cbee56eef5254f Mon Sep 17 00:00:00 2001 From: edgd1er Date: Fri, 15 Oct 2021 01:47:18 +0200 Subject: [PATCH 1/7] lint dockerfile, set TZ and UID/GID, have client log. --- docker/docker-py3-kms-minimal/Dockerfile | 15 ++-- docker/docker-py3-kms/Dockerfile | 74 +++++++++++-------- docker/entrypoint.py | 45 +++++++++--- docker/start.py | 90 ++++++++++++++++++++++++ 4 files changed, 175 insertions(+), 49 deletions(-) create mode 100644 docker/start.py diff --git a/docker/docker-py3-kms-minimal/Dockerfile b/docker/docker-py3-kms-minimal/Dockerfile index 25a28af..ecb2668 100644 --- a/docker/docker-py3-kms-minimal/Dockerfile +++ b/docker/docker-py3-kms-minimal/Dockerfile @@ -1,6 +1,5 @@ # This is a minimized version from docker/docker-py3-kms/Dockerfile without SQLite support to further reduce image size - -FROM alpine:3.12 +FROM alpine:3.14 ENV IP 0.0.0.0 ENV PORT 1688 @@ -11,7 +10,7 @@ ENV ACTIVATION_INTERVAL 120 ENV RENEWAL_INTERVAL 10080 ENV HWID RANDOM ENV LOGLEVEL INFO -ENV LOGFILE /dev/stdout +ENV LOGFILE STDOUT ENV LOGSIZE "" COPY ./py-kms /home/py-kms @@ -27,11 +26,10 @@ RUN apk add --no-cache --update \ py3-pip \ tzdata \ build-base python3-dev && \ - pip3 install peewee tzlocal pytz && \ - apk del git build-base python3-dev - -# Fix undefined timezone, in case the user did not mount the /etc/localtime -RUN cp /usr/share/zoneinfo/UTC /etc/localtime + pip3 install --no-cache peewee tzlocal pytz wheel && \ + apk del git build-base python3-dev && \ + # Fix undefined timezone, in case the user did not mount the /etc/localtime + ln -sf /usr/share/zoneinfo/UTC /etc/localtime WORKDIR /home/py-kms @@ -40,3 +38,4 @@ EXPOSE ${PORT}/tcp COPY docker/entrypoint.py /usr/bin/entrypoint.py RUN chmod a+x /usr/bin/entrypoint.py ENTRYPOINT ["/usr/bin/python3", "/usr/bin/entrypoint.py"] +#CMD["/usr/bin/start.py"] diff --git a/docker/docker-py3-kms/Dockerfile b/docker/docker-py3-kms/Dockerfile index c2ee203..5bfb7d5 100644 --- a/docker/docker-py3-kms/Dockerfile +++ b/docker/docker-py3-kms/Dockerfile @@ -1,4 +1,5 @@ -FROM alpine:3.12 +# Switch to the target image +FROM alpine:3.14 ENV IP 0.0.0.0 ENV PORT 1688 @@ -11,39 +12,52 @@ ENV SQLITE true ENV SQLITE_PORT 8080 ENV HWID RANDOM ENV LOGLEVEL INFO -ENV LOGFILE /dev/stdout +ENV LOGFILE STDOUT ENV LOGSIZE "" +ENV TZ America/Chicago COPY ./py-kms /home/py-kms +#hadolint ignore=DL3013,DL3018 RUN apk add --no-cache --update \ - bash \ - git \ - py3-argparse \ - py3-flask \ - py3-pygments \ - python3-tkinter \ - sqlite-libs \ - py3-pip \ - tzdata \ - build-base python3-dev && \ - git clone https://github.com/coleifer/sqlite-web.git /tmp/sqlite_web && \ - cd /tmp/sqlite_web && \ - git checkout 2e7c85da3d37f80074ed3ae39b5851069b4f301c && \ - cd / && \ - mv /tmp/sqlite_web/sqlite_web /home/ && \ - rm -rf /tmp/sqlite_web && \ - pip3 install peewee tzlocal pytz pysqlite3 && \ - apk del git build-base python3-dev - -# Fix undefined timezone, in case the user did not mount the /etc/localtime -RUN cp /usr/share/zoneinfo/UTC /etc/localtime - -WORKDIR /home/py-kms - -EXPOSE ${SQLITE_PORT}/tcp -EXPOSE ${PORT}/tcp + bash \ + git \ + python3 \ + py3-argparse \ + py3-flask \ + py3-pygments \ + python3-tkinter \ + sqlite-libs \ + py3-pip \ + build-base python3-dev \ + ca-certificates \ + duplicity \ + su-exec \ + sudo \ + tzdata \ + shadow \ + && git clone --branch master --depth 1 https://github.com/coleifer/sqlite-web.git /tmp/sqlite_web \ + && mv /tmp/sqlite_web/sqlite_web /home/ \ + && rm -rf /tmp/sqlite_web \ + && pip3 install --no-cache-dir peewee tzlocal pytz pysqlite3 wheel \ + && apk del git build-base python3-dev \ + && mkdir /db/ \ + && addgroup power_users \ + && adduser -S py-kms -G users -s /bin/bash \ + && usermod -a -G power_users py-kms \ + && chown py-kms:users /home/py-kms \ + # Fix undefined timezone, in case the user did not mount the /etc/localtime + && ln -sf /usr/share/zoneinfo/UTC /etc/localtime COPY docker/entrypoint.py /usr/bin/entrypoint.py -RUN chmod a+x /usr/bin/entrypoint.py -ENTRYPOINT ["/usr/bin/python3", "/usr/bin/entrypoint.py"] +COPY docker/start.py /usr/bin/start.py + +RUN chmod 755 /usr/bin/entrypoint.py + +WORKDIR /home/py-kms +#USER py-kms +EXPOSE ${PORT}/tcp +EXPOSE 8080 + +ENTRYPOINT [ "/usr/bin/python3", "/usr/bin/entrypoint.py" ] +CMD ["/usr/bin/start.py"] diff --git a/docker/entrypoint.py b/docker/entrypoint.py index bd0805e..d886c92 100755 --- a/docker/entrypoint.py +++ b/docker/entrypoint.py @@ -1,9 +1,10 @@ #!/usr/bin/python3 -# This replaces the old start.sh and ensures all arguments are bound correctly from the environment variables... +# Need root privileges to change timezone, and user uid/gid +import grp import os -import time +import pwd import subprocess argumentVariableMapping = { @@ -19,6 +20,21 @@ argumentVariableMapping = { } sqliteWebPath = '/home/sqlite_web/sqlite_web.py' +def change_uid_grp(): + user_db_entries = pwd.getpwnam("py-kms") + user_grp_db_entries = grp.getgrnam("power_users") + uid = user_db_entries.pw_uid + gid = user_grp_db_entries.gr_gid + new_gid = int(os.getenv('GID', str(gid))) + new_uid = int(os.getenv('UID', str(uid))) + os.chown("/home/py-kms", new_uid, new_uid) + os.chown("/db/pykms_database.db", new_uid, new_uid) + if gid != new_gid: + print("Setting gid to " + str(new_gid), flush=True) + os.setgid(gid) + if uid != new_uid: + print("Setting uid to " + str(new_uid), flush=True) + os.setuid(uid) # Build the command to execute listenIP = os.environ.get('IP', '0.0.0.0') listenPort = os.environ.get('PORT', '1688') @@ -36,8 +52,14 @@ if enableSQLITE: command.append('-s') command.append(dbPath) -pykmsProcess = subprocess.Popen(command) +def change_tz(): + tz = os.getenv('TZ', 'etc/UTC') + # TZ is not symlinked and defined TZ exists + if tz not in os.readlink(LTIME) and os.path.isfile('/usr/share/zoneinfo/' + tz): + print("Setting timezone to " + tz, flush=True) + os.remove(LTIME) + os.symlink(os.path.join('/usr/share/zoneinfo/', tz), LTIME) # In case SQLITE is defined: Start the web interface if enableSQLITE: time.sleep(5) # The server may take a while to start @@ -46,12 +68,13 @@ if enableSQLITE: subprocess.run(['/usr/bin/python3', 'pykms_Client.py', listenIP, listenPort, '-m', 'Windows10', '-n', 'DummyClient', '-c', 'ae3a27d1-b73a-4734-9878-70c949815218']) sqliteProcess = subprocess.Popen(['/usr/bin/python3', sqliteWebPath, '-H', listenIP, '--read-only', '-x', dbPath, '-p', os.environ.get('SQLITE_PORT', 8080)]) -try: - pykmsProcess.wait() -except: - # In case of any error - just shut down - pass -if enableSQLITE: - sqliteProcess.terminate() - pykmsProcess.terminate() +LTIME = '/etc/localtime' +PYTHON3 = '/usr/bin/python3' +log_level = os.getenv('LOGLEVEL', 'INFO') + +# Main +if (__name__ == "__main__"): + change_tz() + change_uid_grp() + subprocess.call("/usr/bin/start.py",shell=True) diff --git a/docker/start.py b/docker/start.py new file mode 100644 index 0000000..7bb3309 --- /dev/null +++ b/docker/start.py @@ -0,0 +1,90 @@ +#!/usr/bin/python3 + +# This replaces the old start.sh and ensures all arguments are bound correctly from the environment variables... + +import os +import subprocess +import time + +LTIME = '/etc/localtime' +PYTHON3 = '/usr/bin/python3' +argumentVariableMapping = { + '-l': 'LCID', + '-c': 'CLIENT_COUNT', + '-a': 'ACTIVATION_INTERVAL', + '-r': 'RENEWAL_INTERVAL', + '-w': 'HWID', + '-V': 'LOGLEVEL', + '-F': 'LOGFILE', + '-S': 'LOGSIZE', + '-e': 'EPID' +} +enableSQLITE = os.getenv('SQLITE', 'false').lower() == 'true' +dbPath = os.path.join('/db/pykms_database.db') +log_level = os.getenv('LOGLEVEL', 'INFO') + + +def start_kms_client(): + time.sleep(5) # The server may take a while to start + if not os.path.isfile(dbPath): + # Start a dummy activation to ensure the database file is created + client_cmd = [PYTHON3, 'pykms_Client.py', os.environ.get('IP', "0.0.0.0"), os.environ.get('PORT', 1688), + '-m', 'Windows10', '-n', 'DummyClient', '-c', 'ae3a27d1-b73a-4734-9878-70c949815218', + '-V', os.environ.get('LOGLEVEL', 'INFO'), '-F', os.environ.get('LOGFILE', 'STDOUT')] + if os.environ.get('LOGSIZE', '') != "": + client_cmd.append('-S') + client_cmd.append(os.environ.get('LOGSIZE')) + + if log_level.lower() in ['info', 'debug']: + print("Starting a dummy activation to ensure the database file is created", flush=True) + if log_level.lower() == 'debug': + print("client_cmd: " + str(client_cmd), flush=True) + + subprocess.run(client_cmd) + + +def start_kms(): + # Build the command to execute + command = [PYTHON3, 'pykms_Server.py', os.environ.get('IP'), os.environ.get('PORT')] + for (arg, env) in argumentVariableMapping.items(): + if env in os.environ and os.environ.get(env) != '': + command.append(arg) + command.append(os.environ.get(env)) + + os.makedirs(os.path.dirname(dbPath), exist_ok=True) + + if enableSQLITE: + print('Storing database file to ' + dbPath, flush=True) + command.append('-s') + command.append(dbPath) + + if log_level.lower() == 'debug': + print("server_cmd: " + str(command), flush=True) + + pykms_process = subprocess.Popen(command) + + # In case SQLITE is defined: Start the web interface + if enableSQLITE: + start_kms_client() + sqlite_cmd = [PYTHON3, '/home/sqlite_web/sqlite_web.py', '-H', os.environ.get('IP'), '--read-only', '-x', dbPath, + '-p', os.environ.get('SQLITE_PORT')] + + if log_level.lower() == 'debug': + print("sqlite_cmd: " + str(sqlite_cmd), flush=True) + + sqlite_process = subprocess.Popen(sqlite_cmd) + + try: + pykms_process.wait() + except Exception: + # In case of any error - just shut down + pass + + if enableSQLITE: + sqlite_process.terminate() + pykms_process.terminate() + + +# Main +if (__name__ == "__main__"): + start_kms() From d2394cd1bd5ece2dbac98c33701bd89345f7afba Mon Sep 17 00:00:00 2001 From: edgd1er Date: Fri, 22 Oct 2021 23:39:31 +0200 Subject: [PATCH 2/7] start as root, change uid/gid, drop priv, run server/client --- docker/docker-py3-kms/Dockerfile | 4 +-- docker/entrypoint.py | 58 +++++++------------------------- docker/start.py | 12 +++---- 3 files changed, 19 insertions(+), 55 deletions(-) diff --git a/docker/docker-py3-kms/Dockerfile b/docker/docker-py3-kms/Dockerfile index 5bfb7d5..629d5b0 100644 --- a/docker/docker-py3-kms/Dockerfile +++ b/docker/docker-py3-kms/Dockerfile @@ -32,8 +32,6 @@ RUN apk add --no-cache --update \ build-base python3-dev \ ca-certificates \ duplicity \ - su-exec \ - sudo \ tzdata \ shadow \ && git clone --branch master --depth 1 https://github.com/coleifer/sqlite-web.git /tmp/sqlite_web \ @@ -56,7 +54,7 @@ RUN chmod 755 /usr/bin/entrypoint.py WORKDIR /home/py-kms #USER py-kms -EXPOSE ${PORT}/tcp +EXPOSE 1688/tcp EXPOSE 8080 ENTRYPOINT [ "/usr/bin/python3", "/usr/bin/entrypoint.py" ] diff --git a/docker/entrypoint.py b/docker/entrypoint.py index d886c92..3250225 100755 --- a/docker/entrypoint.py +++ b/docker/entrypoint.py @@ -7,18 +7,10 @@ import os import pwd import subprocess -argumentVariableMapping = { - '-l': 'LCID', - '-c': 'CLIENT_COUNT', - '-a': 'ACTIVATION_INTERVAL', - '-r': 'RENEWAL_INTERVAL', - '-w': 'HWID', - '-V': 'LOGLEVEL', - '-F': 'LOGFILE', - '-S': 'LOGSIZE', - '-e': 'EPID' -} -sqliteWebPath = '/home/sqlite_web/sqlite_web.py' +PYTHON3 = '/usr/bin/python3' +dbPath = os.path.join(os.sep, 'home', 'py-kms', 'db', 'pykms_database.db') +log_level = os.getenv('LOGLEVEL', 'INFO') + def change_uid_grp(): user_db_entries = pwd.getpwnam("py-kms") @@ -27,54 +19,28 @@ def change_uid_grp(): gid = user_grp_db_entries.gr_gid new_gid = int(os.getenv('GID', str(gid))) new_uid = int(os.getenv('UID', str(uid))) - os.chown("/home/py-kms", new_uid, new_uid) - os.chown("/db/pykms_database.db", new_uid, new_uid) + os.chown("/home/py-kms", new_uid, new_gid) + os.chown("/usr/bin/start.py", new_uid, new_gid) + if os.path.isfile(dbPath): os.chown(dbPath, new_uid, new_gid) + os.system("ls -al /usr/bin/start.py") if gid != new_gid: print("Setting gid to " + str(new_gid), flush=True) os.setgid(gid) if uid != new_uid: print("Setting uid to " + str(new_uid), flush=True) os.setuid(uid) -# Build the command to execute -listenIP = os.environ.get('IP', '0.0.0.0') -listenPort = os.environ.get('PORT', '1688') -command = ['/usr/bin/python3', 'pykms_Server.py', listenIP, listenPort] -for (arg, env) in argumentVariableMapping.items(): - if env in os.environ and os.environ.get(env) != '': - command.append(arg) - command.append(os.environ.get(env)) - -enableSQLITE = os.path.isfile(sqliteWebPath) and os.environ.get('SQLITE', 'false').lower() == 'true' -if enableSQLITE: - dbPath = os.path.join('db', 'pykms_database.db') - print('Storing database file to ' + dbPath) - os.makedirs('db', exist_ok=True) - command.append('-s') - command.append(dbPath) def change_tz(): tz = os.getenv('TZ', 'etc/UTC') # TZ is not symlinked and defined TZ exists - if tz not in os.readlink(LTIME) and os.path.isfile('/usr/share/zoneinfo/' + tz): + if tz not in os.readlink('/etc/localtime') and os.path.isfile('/usr/share/zoneinfo/' + tz): print("Setting timezone to " + tz, flush=True) - os.remove(LTIME) - os.symlink(os.path.join('/usr/share/zoneinfo/', tz), LTIME) -# In case SQLITE is defined: Start the web interface -if enableSQLITE: - time.sleep(5) # The server may take a while to start - if not os.path.isfile(dbPath): - # Start a dummy activation to ensure the database file is created - subprocess.run(['/usr/bin/python3', 'pykms_Client.py', listenIP, listenPort, '-m', 'Windows10', '-n', 'DummyClient', '-c', 'ae3a27d1-b73a-4734-9878-70c949815218']) - sqliteProcess = subprocess.Popen(['/usr/bin/python3', sqliteWebPath, '-H', listenIP, '--read-only', '-x', dbPath, '-p', os.environ.get('SQLITE_PORT', 8080)]) + os.remove('/etc/localtime') + os.symlink(os.path.join('/usr/share/zoneinfo/', tz), '/etc/localtime') -LTIME = '/etc/localtime' -PYTHON3 = '/usr/bin/python3' -log_level = os.getenv('LOGLEVEL', 'INFO') - # Main if (__name__ == "__main__"): change_tz() - change_uid_grp() - subprocess.call("/usr/bin/start.py",shell=True) + subprocess.call(PYTHON3 + " /usr/bin/start.py", preexec_fn=change_uid_grp(), shell=True) diff --git a/docker/start.py b/docker/start.py index 7bb3309..8de8d57 100644 --- a/docker/start.py +++ b/docker/start.py @@ -1,7 +1,6 @@ #!/usr/bin/python3 # This replaces the old start.sh and ensures all arguments are bound correctly from the environment variables... - import os import subprocess import time @@ -19,13 +18,14 @@ argumentVariableMapping = { '-S': 'LOGSIZE', '-e': 'EPID' } -enableSQLITE = os.getenv('SQLITE', 'false').lower() == 'true' -dbPath = os.path.join('/db/pykms_database.db') + +sqliteWebPath = '/home/sqlite_web/sqlite_web.py' +enableSQLITE = os.path.isfile(sqliteWebPath) and os.environ.get('SQLITE', 'false').lower() == 'true' +dbPath = os.path.join(os.sep, 'home', 'py-kms', 'db', 'pykms_database.db') log_level = os.getenv('LOGLEVEL', 'INFO') def start_kms_client(): - time.sleep(5) # The server may take a while to start if not os.path.isfile(dbPath): # Start a dummy activation to ensure the database file is created client_cmd = [PYTHON3, 'pykms_Client.py', os.environ.get('IP', "0.0.0.0"), os.environ.get('PORT', 1688), @@ -51,8 +51,6 @@ def start_kms(): command.append(arg) command.append(os.environ.get(env)) - os.makedirs(os.path.dirname(dbPath), exist_ok=True) - if enableSQLITE: print('Storing database file to ' + dbPath, flush=True) command.append('-s') @@ -65,6 +63,8 @@ def start_kms(): # In case SQLITE is defined: Start the web interface if enableSQLITE: + time.sleep(5) # The server may take a while to start + os.system('ls -al ' + dbPath) start_kms_client() sqlite_cmd = [PYTHON3, '/home/sqlite_web/sqlite_web.py', '-H', os.environ.get('IP'), '--read-only', '-x', dbPath, '-p', os.environ.get('SQLITE_PORT')] From 6d7124414a6b270c7e6749c89ab8169d54f7d11e Mon Sep 17 00:00:00 2001 From: edgd1er Date: Sat, 23 Oct 2021 08:54:48 +0200 Subject: [PATCH 3/7] use unbuffered output globally. --- docker/entrypoint.py | 12 ++++++------ docker/start.py | 19 +++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/docker/entrypoint.py b/docker/entrypoint.py index 3250225..06dda71 100755 --- a/docker/entrypoint.py +++ b/docker/entrypoint.py @@ -1,6 +1,6 @@ -#!/usr/bin/python3 +#!/usr/bin/python3 -u -# Need root privileges to change timezone, and user uid/gid +# Need root privileges to change timezone, and user uid/gid, file/folder ownernship import grp import os @@ -24,10 +24,10 @@ def change_uid_grp(): if os.path.isfile(dbPath): os.chown(dbPath, new_uid, new_gid) os.system("ls -al /usr/bin/start.py") if gid != new_gid: - print("Setting gid to " + str(new_gid), flush=True) + print("Setting gid to " + str(new_gid)) os.setgid(gid) if uid != new_uid: - print("Setting uid to " + str(new_uid), flush=True) + print("Setting uid to " + str(new_uid)) os.setuid(uid) @@ -35,7 +35,7 @@ def change_tz(): tz = os.getenv('TZ', 'etc/UTC') # TZ is not symlinked and defined TZ exists if tz not in os.readlink('/etc/localtime') and os.path.isfile('/usr/share/zoneinfo/' + tz): - print("Setting timezone to " + tz, flush=True) + print("Setting timezone to " + tz) os.remove('/etc/localtime') os.symlink(os.path.join('/usr/share/zoneinfo/', tz), '/etc/localtime') @@ -43,4 +43,4 @@ def change_tz(): # Main if (__name__ == "__main__"): change_tz() - subprocess.call(PYTHON3 + " /usr/bin/start.py", preexec_fn=change_uid_grp(), shell=True) + subprocess.call(PYTHON3 + " -u /usr/bin/start.py", preexec_fn=change_uid_grp(), shell=True) diff --git a/docker/start.py b/docker/start.py index 8de8d57..861adff 100644 --- a/docker/start.py +++ b/docker/start.py @@ -1,11 +1,10 @@ -#!/usr/bin/python3 +#!/usr/bin/python3 -u # This replaces the old start.sh and ensures all arguments are bound correctly from the environment variables... import os import subprocess import time -LTIME = '/etc/localtime' PYTHON3 = '/usr/bin/python3' argumentVariableMapping = { '-l': 'LCID', @@ -28,7 +27,7 @@ log_level = os.getenv('LOGLEVEL', 'INFO') def start_kms_client(): if not os.path.isfile(dbPath): # Start a dummy activation to ensure the database file is created - client_cmd = [PYTHON3, 'pykms_Client.py', os.environ.get('IP', "0.0.0.0"), os.environ.get('PORT', 1688), + client_cmd = [PYTHON3,'-u', 'pykms_Client.py', os.environ.get('IP', "0.0.0.0"), os.environ.get('PORT', 1688), '-m', 'Windows10', '-n', 'DummyClient', '-c', 'ae3a27d1-b73a-4734-9878-70c949815218', '-V', os.environ.get('LOGLEVEL', 'INFO'), '-F', os.environ.get('LOGFILE', 'STDOUT')] if os.environ.get('LOGSIZE', '') != "": @@ -36,28 +35,28 @@ def start_kms_client(): client_cmd.append(os.environ.get('LOGSIZE')) if log_level.lower() in ['info', 'debug']: - print("Starting a dummy activation to ensure the database file is created", flush=True) + print("Starting a dummy activation to ensure the database file is created") if log_level.lower() == 'debug': - print("client_cmd: " + str(client_cmd), flush=True) + print("client_cmd: " + str(client_cmd)) subprocess.run(client_cmd) def start_kms(): # Build the command to execute - command = [PYTHON3, 'pykms_Server.py', os.environ.get('IP'), os.environ.get('PORT')] + command = [PYTHON3,'-u', 'pykms_Server.py', os.environ.get('IP'), os.environ.get('PORT')] for (arg, env) in argumentVariableMapping.items(): if env in os.environ and os.environ.get(env) != '': command.append(arg) command.append(os.environ.get(env)) if enableSQLITE: - print('Storing database file to ' + dbPath, flush=True) + print('Storing database file to ' + dbPath) command.append('-s') command.append(dbPath) if log_level.lower() == 'debug': - print("server_cmd: " + str(command), flush=True) + print("server_cmd: " + str(command)) pykms_process = subprocess.Popen(command) @@ -66,11 +65,11 @@ def start_kms(): time.sleep(5) # The server may take a while to start os.system('ls -al ' + dbPath) start_kms_client() - sqlite_cmd = [PYTHON3, '/home/sqlite_web/sqlite_web.py', '-H', os.environ.get('IP'), '--read-only', '-x', dbPath, + sqlite_cmd = [PYTHON3,'-u', '/home/sqlite_web/sqlite_web.py', '-H', os.environ.get('IP'), '--read-only', '-x', dbPath, '-p', os.environ.get('SQLITE_PORT')] if log_level.lower() == 'debug': - print("sqlite_cmd: " + str(sqlite_cmd), flush=True) + print("sqlite_cmd: " + str(sqlite_cmd)) sqlite_process = subprocess.Popen(sqlite_cmd) From 5f7ef1397f8ce98e35bd2a834797bffb54f02efe Mon Sep 17 00:00:00 2001 From: edgd1er Date: Mon, 25 Oct 2021 23:57:57 +0200 Subject: [PATCH 4/7] add proper logger to entrypoint and start --- docker/entrypoint.py | 25 +++++++++++++++++++------ docker/start.py | 37 +++++++++++++++++++++---------------- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/docker/entrypoint.py b/docker/entrypoint.py index 06dda71..3ccfb58 100755 --- a/docker/entrypoint.py +++ b/docker/entrypoint.py @@ -3,31 +3,43 @@ # Need root privileges to change timezone, and user uid/gid, file/folder ownernship import grp +import logging import os import pwd import subprocess +import sys PYTHON3 = '/usr/bin/python3' dbPath = os.path.join(os.sep, 'home', 'py-kms', 'db', 'pykms_database.db') log_level = os.getenv('LOGLEVEL', 'INFO') +loggersrv = logging.getLogger('logsrv') +loggersrv.setLevel(log_level) +streamhandler = logging.StreamHandler(sys.stdout) +streamhandler.setLevel(log_level) +formatter = logging.Formatter(fmt = '\x1b[94m%(asctime)s %(levelname)-8s %(message)s', + datefmt = '%a, %d %b %Y %H:%M:%S',) +streamhandler.setFormatter(formatter) +loggersrv.addHandler(streamhandler) + def change_uid_grp(): user_db_entries = pwd.getpwnam("py-kms") user_grp_db_entries = grp.getgrnam("power_users") - uid = user_db_entries.pw_uid - gid = user_grp_db_entries.gr_gid + uid = int(user_db_entries.pw_uid) + gid = int(user_grp_db_entries.gr_gid) new_gid = int(os.getenv('GID', str(gid))) new_uid = int(os.getenv('UID', str(uid))) os.chown("/home/py-kms", new_uid, new_gid) os.chown("/usr/bin/start.py", new_uid, new_gid) if os.path.isfile(dbPath): os.chown(dbPath, new_uid, new_gid) - os.system("ls -al /usr/bin/start.py") + loggersrv.debug("%s" %str(subprocess.check_output("ls -al " + dbPath, shell=True))) if gid != new_gid: - print("Setting gid to " + str(new_gid)) + loggersrv.info("Setting gid to '%s'." % str(new_gid)) os.setgid(gid) + if uid != new_uid: - print("Setting uid to " + str(new_uid)) + loggersrv.info("Setting uid to '%s'." % str(new_uid)) os.setuid(uid) @@ -35,12 +47,13 @@ def change_tz(): tz = os.getenv('TZ', 'etc/UTC') # TZ is not symlinked and defined TZ exists if tz not in os.readlink('/etc/localtime') and os.path.isfile('/usr/share/zoneinfo/' + tz): - print("Setting timezone to " + tz) + loggersrv.info("Setting timzeone to %s" % tz ) os.remove('/etc/localtime') os.symlink(os.path.join('/usr/share/zoneinfo/', tz), '/etc/localtime') # Main if (__name__ == "__main__"): + loggersrv.info("Log level: %s" % log_level) change_tz() subprocess.call(PYTHON3 + " -u /usr/bin/start.py", preexec_fn=change_uid_grp(), shell=True) diff --git a/docker/start.py b/docker/start.py index 861adff..3b2a318 100644 --- a/docker/start.py +++ b/docker/start.py @@ -1,8 +1,10 @@ #!/usr/bin/python3 -u # This replaces the old start.sh and ensures all arguments are bound correctly from the environment variables... +import logging import os import subprocess +import sys import time PYTHON3 = '/usr/bin/python3' @@ -27,50 +29,45 @@ log_level = os.getenv('LOGLEVEL', 'INFO') def start_kms_client(): if not os.path.isfile(dbPath): # Start a dummy activation to ensure the database file is created - client_cmd = [PYTHON3,'-u', 'pykms_Client.py', os.environ.get('IP', "0.0.0.0"), os.environ.get('PORT', 1688), + client_cmd = [PYTHON3, '-u', 'pykms_Client.py', os.environ.get('IP', "0.0.0.0"), os.environ.get('PORT', 1688), '-m', 'Windows10', '-n', 'DummyClient', '-c', 'ae3a27d1-b73a-4734-9878-70c949815218', '-V', os.environ.get('LOGLEVEL', 'INFO'), '-F', os.environ.get('LOGFILE', 'STDOUT')] if os.environ.get('LOGSIZE', '') != "": client_cmd.append('-S') client_cmd.append(os.environ.get('LOGSIZE')) - if log_level.lower() in ['info', 'debug']: - print("Starting a dummy activation to ensure the database file is created") - if log_level.lower() == 'debug': - print("client_cmd: " + str(client_cmd)) + loggersrv.info("Starting a dummy activation to ensure the database file is created") + loggersrv.debug("client_cmd: %s" % (" ".join(str(x) for x in client_cmd).strip())) subprocess.run(client_cmd) def start_kms(): + sqlite_process = None # Build the command to execute - command = [PYTHON3,'-u', 'pykms_Server.py', os.environ.get('IP'), os.environ.get('PORT')] + command = [PYTHON3, '-u', 'pykms_Server.py', os.environ.get('IP'), os.environ.get('PORT')] for (arg, env) in argumentVariableMapping.items(): if env in os.environ and os.environ.get(env) != '': command.append(arg) command.append(os.environ.get(env)) if enableSQLITE: - print('Storing database file to ' + dbPath) + loggersrv.info("Storing database file to %s" % dbPath) command.append('-s') command.append(dbPath) - if log_level.lower() == 'debug': - print("server_cmd: " + str(command)) - + loggersrv.debug("server_cmd: %s" % (" ".join(str(x) for x in command).strip())) pykms_process = subprocess.Popen(command) # In case SQLITE is defined: Start the web interface if enableSQLITE: time.sleep(5) # The server may take a while to start - os.system('ls -al ' + dbPath) start_kms_client() - sqlite_cmd = [PYTHON3,'-u', '/home/sqlite_web/sqlite_web.py', '-H', os.environ.get('IP'), '--read-only', '-x', dbPath, + sqlite_cmd = [PYTHON3, '-u', '/home/sqlite_web/sqlite_web.py', '-H', os.environ.get('IP'), '--read-only', '-x', + dbPath, '-p', os.environ.get('SQLITE_PORT')] - if log_level.lower() == 'debug': - print("sqlite_cmd: " + str(sqlite_cmd)) - + loggersrv.debug("sqlite_cmd: %s" % (" ".join(str(x) for x in sqlite_cmd).strip())) sqlite_process = subprocess.Popen(sqlite_cmd) try: @@ -80,10 +77,18 @@ def start_kms(): pass if enableSQLITE: - sqlite_process.terminate() + if None != sqlite_process: sqlite_process.terminate() pykms_process.terminate() # Main if (__name__ == "__main__"): + loggersrv = logging.getLogger('logsrv') + loggersrv.setLevel(log_level) + streamhandler = logging.StreamHandler(sys.stdout) + streamhandler.setLevel(log_level) + formatter = logging.Formatter(fmt='\x1b[94m%(asctime)s %(levelname)-8s %(message)s', + datefmt='%a, %d %b %Y %H:%M:%S') + streamhandler.setFormatter(formatter) + loggersrv.addHandler(streamhandler) start_kms() From a564822e26d117028d46fdbbea6f4ec18c172194 Mon Sep 17 00:00:00 2001 From: edgd1er Date: Tue, 26 Oct 2021 22:56:47 +0200 Subject: [PATCH 5/7] add healthcheck with netcap checking port --- .dockerignore | 8 ++++++++ .gitignore | 5 ++++- docker/docker-py3-kms-minimal/Dockerfile | 15 +++++++++++---- docker/docker-py3-kms/Dockerfile | 10 ++++++---- 4 files changed, 29 insertions(+), 9 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..54d0d69 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +log/ +.idea +.github +*.db +*.yml +*.md +*.sh +Makefile diff --git a/.gitignore b/.gitignore index a149ec6..874f86a 100644 --- a/.gitignore +++ b/.gitignore @@ -129,4 +129,7 @@ dmypy.json .pyre/ # Helm -charts/*/*.tgz \ No newline at end of file +charts/*/*.tgz +/.idea/ +docker-compose-*.yml +*.sh diff --git a/docker/docker-py3-kms-minimal/Dockerfile b/docker/docker-py3-kms-minimal/Dockerfile index ecb2668..e4cd8ed 100644 --- a/docker/docker-py3-kms-minimal/Dockerfile +++ b/docker/docker-py3-kms-minimal/Dockerfile @@ -24,12 +24,17 @@ RUN apk add --no-cache --update \ python3-tkinter \ sqlite-libs \ py3-pip \ - tzdata \ + tzdata \ + netcat-openbsd \ build-base python3-dev && \ pip3 install --no-cache peewee tzlocal pytz wheel && \ apk del git build-base python3-dev && \ + && addgroup power_users \ + && adduser -S py-kms -G users -s /bin/bash \ + && usermod -a -G power_users py-kms \ + && chown py-kms:users /home/py-kms \ # Fix undefined timezone, in case the user did not mount the /etc/localtime - ln -sf /usr/share/zoneinfo/UTC /etc/localtime + && ln -sf /usr/share/zoneinfo/UTC /etc/localtime WORKDIR /home/py-kms @@ -37,5 +42,7 @@ EXPOSE ${PORT}/tcp COPY docker/entrypoint.py /usr/bin/entrypoint.py RUN chmod a+x /usr/bin/entrypoint.py -ENTRYPOINT ["/usr/bin/python3", "/usr/bin/entrypoint.py"] -#CMD["/usr/bin/start.py"] +HEALTHCHECK --interval=5m --timeout=3s --start-period=10s --retries=4 CMD echo | nc -t localhost ${PORT} || exit 1 + +ENTRYPOINT ["/usr/bin/python3", "-u","/usr/bin/entrypoint.py"] +CMD["/usr/bin/start.py"] diff --git a/docker/docker-py3-kms/Dockerfile b/docker/docker-py3-kms/Dockerfile index 629d5b0..c4221ac 100644 --- a/docker/docker-py3-kms/Dockerfile +++ b/docker/docker-py3-kms/Dockerfile @@ -16,8 +16,7 @@ ENV LOGFILE STDOUT ENV LOGSIZE "" ENV TZ America/Chicago -COPY ./py-kms /home/py-kms - +COPY py-kms /home/py-kms/ #hadolint ignore=DL3013,DL3018 RUN apk add --no-cache --update \ bash \ @@ -34,6 +33,7 @@ RUN apk add --no-cache --update \ duplicity \ tzdata \ shadow \ + netcat-openbsd \ && git clone --branch master --depth 1 https://github.com/coleifer/sqlite-web.git /tmp/sqlite_web \ && mv /tmp/sqlite_web/sqlite_web /home/ \ && rm -rf /tmp/sqlite_web \ @@ -54,8 +54,10 @@ RUN chmod 755 /usr/bin/entrypoint.py WORKDIR /home/py-kms #USER py-kms -EXPOSE 1688/tcp +EXPOSE ${PORT}/tcp EXPOSE 8080 -ENTRYPOINT [ "/usr/bin/python3", "/usr/bin/entrypoint.py" ] +HEALTHCHECK --interval=5m --timeout=3s --start-period=10s --retries=4 CMD echo | nc -t localhost ${PORT} || exit 1 + +ENTRYPOINT [ "/usr/bin/python3","-u","/usr/bin/entrypoint.py" ] CMD ["/usr/bin/start.py"] From 2979e783111440737ba02c556c368cdde9bb1a48 Mon Sep 17 00:00:00 2001 From: edgd1er Date: Fri, 29 Oct 2021 18:53:52 +0200 Subject: [PATCH 6/7] add missing setting to timzeone. --- docker/entrypoint.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docker/entrypoint.py b/docker/entrypoint.py index 3ccfb58..17cff0e 100755 --- a/docker/entrypoint.py +++ b/docker/entrypoint.py @@ -50,6 +50,9 @@ def change_tz(): loggersrv.info("Setting timzeone to %s" % tz ) os.remove('/etc/localtime') os.symlink(os.path.join('/usr/share/zoneinfo/', tz), '/etc/localtime') + f = open("/etc/timezone", "w") + f.write(tz) + f.close() # Main From 51e2210e72e333fc24b5d360069dcb97b03ff360 Mon Sep 17 00:00:00 2001 From: edgd1er Date: Sat, 30 Oct 2021 12:41:11 +0200 Subject: [PATCH 7/7] var added as requested and renamed as per PEP-008 https://www.python.org/dev/peps/pep-0008/#function-and-variable-names --- docker/start.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/docker/start.py b/docker/start.py index 3b2a318..625cf2f 100644 --- a/docker/start.py +++ b/docker/start.py @@ -24,18 +24,21 @@ sqliteWebPath = '/home/sqlite_web/sqlite_web.py' enableSQLITE = os.path.isfile(sqliteWebPath) and os.environ.get('SQLITE', 'false').lower() == 'true' dbPath = os.path.join(os.sep, 'home', 'py-kms', 'db', 'pykms_database.db') log_level = os.getenv('LOGLEVEL', 'INFO') +log_file = os.environ.get('LOGFILE', 'STDOUT') +listen_ip = os.environ.get('IP', '0.0.0.0') +listen_port = os.environ.get('PORT', '1688') +sqlite_port = os.environ.get('SQLITE_PORT', '8080') def start_kms_client(): if not os.path.isfile(dbPath): # Start a dummy activation to ensure the database file is created - client_cmd = [PYTHON3, '-u', 'pykms_Client.py', os.environ.get('IP', "0.0.0.0"), os.environ.get('PORT', 1688), + client_cmd = [PYTHON3, '-u', 'pykms_Client.py', listen_ip, listen_port, '-m', 'Windows10', '-n', 'DummyClient', '-c', 'ae3a27d1-b73a-4734-9878-70c949815218', - '-V', os.environ.get('LOGLEVEL', 'INFO'), '-F', os.environ.get('LOGFILE', 'STDOUT')] + '-V', log_level, '-F', log_file] if os.environ.get('LOGSIZE', '') != "": client_cmd.append('-S') client_cmd.append(os.environ.get('LOGSIZE')) - loggersrv.info("Starting a dummy activation to ensure the database file is created") loggersrv.debug("client_cmd: %s" % (" ".join(str(x) for x in client_cmd).strip())) @@ -45,7 +48,7 @@ def start_kms_client(): def start_kms(): sqlite_process = None # Build the command to execute - command = [PYTHON3, '-u', 'pykms_Server.py', os.environ.get('IP'), os.environ.get('PORT')] + command = [PYTHON3, '-u', 'pykms_Server.py', listen_ip, listen_port] for (arg, env) in argumentVariableMapping.items(): if env in os.environ and os.environ.get(env) != '': command.append(arg) @@ -55,6 +58,7 @@ def start_kms(): loggersrv.info("Storing database file to %s" % dbPath) command.append('-s') command.append(dbPath) + os.makedirs(os.path.dirname(dbPath), exist_ok=True) loggersrv.debug("server_cmd: %s" % (" ".join(str(x) for x in command).strip())) pykms_process = subprocess.Popen(command) @@ -63,9 +67,8 @@ def start_kms(): if enableSQLITE: time.sleep(5) # The server may take a while to start start_kms_client() - sqlite_cmd = [PYTHON3, '-u', '/home/sqlite_web/sqlite_web.py', '-H', os.environ.get('IP'), '--read-only', '-x', - dbPath, - '-p', os.environ.get('SQLITE_PORT')] + sqlite_cmd = [PYTHON3, '-u', '/home/sqlite_web/sqlite_web.py', '-H', listen_ip, '--read-only', '-x', + dbPath, '-p', sqlite_port] loggersrv.debug("sqlite_cmd: %s" % (" ".join(str(x) for x in sqlite_cmd).strip())) sqlite_process = subprocess.Popen(sqlite_cmd)