From 1592dfd139d91493284a96b43e680eba1fe6ba07 Mon Sep 17 00:00:00 2001 From: AnsibleGuy Date: Wed, 17 Jan 2024 21:27:14 +0100 Subject: [PATCH] fixes for pip-build, lint fixes --- .github/workflows/lint.yml | 4 +- .github/workflows/release.yml | 11 ++-- .github/workflows/test.yml | 10 ++-- .gitignore | 3 +- .pylintrc | 14 ++++- ansible-webui/aw/permission.py | 20 ------- ansible-webui/main.py | 56 ------------------- pyproject.toml | 31 +++++++++- scripts/migrate_db.sh | 2 +- scripts/run_pip_build.sh | 3 + scripts/run_shared.sh | 11 +++- scripts/update_version.sh | 9 +++ setup.py | 29 ---------- .../ansible-webui}/__init__.py | 0 .../ansible-webui}/__main__.py | 3 +- .../ansible-webui}/aw/__init__.py | 0 .../ansible-webui}/aw/admin.py | 0 .../ansible-webui}/aw/apps.py | 0 .../ansible-webui}/aw/config/__init__.py | 0 .../ansible-webui}/aw/config/environment.py | 0 .../ansible-webui}/aw/config/hardcoded.py | 8 --- .../ansible-webui}/aw/config/main.py | 5 ++ .../ansible-webui}/aw/config/navigation.py | 3 +- .../ansible-webui}/aw/execute/__init__.py | 0 .../ansible-webui}/aw/execute/play.py | 0 .../ansible-webui}/aw/execute/util.py | 4 +- .../ansible-webui}/aw/main.py | 0 .../ansible-webui}/aw/migrations/__init__.py | 0 .../ansible-webui}/aw/model/__init__.py | 0 .../ansible-webui}/aw/model/base.py | 0 .../ansible-webui}/aw/model/job.py | 10 ++-- .../ansible-webui}/aw/models.py | 1 + .../ansible-webui}/aw/route.py | 14 +++-- .../ansible-webui}/aw/settings.py | 4 +- .../ansible-webui}/aw/static/css/aw.css | 0 .../aw/static/css/aw_mobile.css | 0 .../ansible-webui}/aw/templates/body.html | 0 .../aw/templates/error/403.html | 0 .../aw/templates/error/500.html | 0 .../aw/templates/error/js_disabled.html | 0 .../ansible-webui}/aw/templates/fallback.html | 0 .../ansible-webui}/aw/templates/head.html | 0 .../ansible-webui}/aw/templates/nav.html | 0 .../aw/templates/registration/login.html | 0 .../aw/templatetags/__init__.py | 0 .../ansible-webui}/aw/templatetags/util.py | 2 +- .../ansible-webui}/aw/utils/__init__.py | 0 .../ansible-webui}/aw/utils/debug.py | 0 .../ansible-webui}/aw/utils/deployment.py | 0 .../ansible-webui}/aw/utils/handlers.py | 0 .../ansible-webui}/aw/utils/util.py | 2 + .../ansible-webui}/aw/utils/util_test.py | 0 .../ansible-webui}/base/__init__.py | 0 .../ansible-webui}/base/scheduler.py | 39 ++++++++++++- .../ansible-webui}/base/serve_static.py | 3 +- .../ansible-webui}/base/threader.py | 20 +++---- .../ansible-webui}/base/webserver.py | 8 ++- src/ansible-webui/main.py | 21 +++++++ .../ansible-webui}/manage.py | 0 {ansible-webui => src/ansible-webui}/route.py | 0 60 files changed, 180 insertions(+), 170 deletions(-) delete mode 100644 ansible-webui/aw/permission.py delete mode 100644 ansible-webui/main.py create mode 100644 scripts/update_version.sh delete mode 100644 setup.py rename {ansible-webui => src/ansible-webui}/__init__.py (100%) rename {ansible-webui => src/ansible-webui}/__main__.py (86%) rename {ansible-webui => src/ansible-webui}/aw/__init__.py (100%) rename {ansible-webui => src/ansible-webui}/aw/admin.py (100%) rename {ansible-webui => src/ansible-webui}/aw/apps.py (100%) rename {ansible-webui => src/ansible-webui}/aw/config/__init__.py (100%) rename {ansible-webui => src/ansible-webui}/aw/config/environment.py (100%) rename {ansible-webui => src/ansible-webui}/aw/config/hardcoded.py (72%) rename {ansible-webui => src/ansible-webui}/aw/config/main.py (80%) rename {ansible-webui => src/ansible-webui}/aw/config/navigation.py (93%) rename {ansible-webui => src/ansible-webui}/aw/execute/__init__.py (100%) rename {ansible-webui => src/ansible-webui}/aw/execute/play.py (100%) rename {ansible-webui => src/ansible-webui}/aw/execute/util.py (98%) rename {ansible-webui => src/ansible-webui}/aw/main.py (100%) rename {ansible-webui => src/ansible-webui}/aw/migrations/__init__.py (100%) rename {ansible-webui => src/ansible-webui}/aw/model/__init__.py (100%) rename {ansible-webui => src/ansible-webui}/aw/model/base.py (100%) rename {ansible-webui => src/ansible-webui}/aw/model/job.py (96%) rename {ansible-webui => src/ansible-webui}/aw/models.py (85%) rename {ansible-webui => src/ansible-webui}/aw/route.py (84%) rename {ansible-webui => src/ansible-webui}/aw/settings.py (98%) rename {ansible-webui => src/ansible-webui}/aw/static/css/aw.css (100%) rename {ansible-webui => src/ansible-webui}/aw/static/css/aw_mobile.css (100%) rename {ansible-webui => src/ansible-webui}/aw/templates/body.html (100%) rename {ansible-webui => src/ansible-webui}/aw/templates/error/403.html (100%) rename {ansible-webui => src/ansible-webui}/aw/templates/error/500.html (100%) rename {ansible-webui => src/ansible-webui}/aw/templates/error/js_disabled.html (100%) rename {ansible-webui => src/ansible-webui}/aw/templates/fallback.html (100%) rename {ansible-webui => src/ansible-webui}/aw/templates/head.html (100%) rename {ansible-webui => src/ansible-webui}/aw/templates/nav.html (100%) rename {ansible-webui => src/ansible-webui}/aw/templates/registration/login.html (100%) rename {ansible-webui => src/ansible-webui}/aw/templatetags/__init__.py (100%) rename {ansible-webui => src/ansible-webui}/aw/templatetags/util.py (93%) rename {ansible-webui => src/ansible-webui}/aw/utils/__init__.py (100%) rename {ansible-webui => src/ansible-webui}/aw/utils/debug.py (100%) rename {ansible-webui => src/ansible-webui}/aw/utils/deployment.py (100%) rename {ansible-webui => src/ansible-webui}/aw/utils/handlers.py (100%) rename {ansible-webui => src/ansible-webui}/aw/utils/util.py (94%) rename {ansible-webui => src/ansible-webui}/aw/utils/util_test.py (100%) rename {ansible-webui => src/ansible-webui}/base/__init__.py (100%) rename {ansible-webui => src/ansible-webui}/base/scheduler.py (64%) rename {ansible-webui => src/ansible-webui}/base/serve_static.py (92%) rename {ansible-webui => src/ansible-webui}/base/threader.py (89%) rename {ansible-webui => src/ansible-webui}/base/webserver.py (91%) create mode 100644 src/ansible-webui/main.py rename {ansible-webui => src/ansible-webui}/manage.py (100%) rename {ansible-webui => src/ansible-webui}/route.py (100%) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 18fbbf8..15e43b0 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -35,8 +35,8 @@ jobs: - name: Install dependencies run: | - pip install -r requirements_lint.txt - pip install -r requirements.txt + pip install -r requirements_lint.txt >/dev/null + pip install -r requirements.txt >/dev/null shell: bash - name: Running PyLint diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b7e1ae5..9da8cc1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -22,20 +22,17 @@ jobs: python-version: '3.10' - name: Install dependencies - run: pip install -r requirements_build.txt + run: pip install -r requirements_build.txt >/dev/null shell: bash - name: Extract tag name id: version run: echo ::set-output name=TAG_NAME::$(echo $GITHUB_REF | cut -d / -f 3 | cut -c 2-) - - name: Update version in setup.py - run: >- - sed -i 's/version=.*/version="${{ steps.version.outputs.TAG_NAME }}",/g' setup.py - sed -i 's/VERSION =.*/VERSION = "${{ steps.version.outputs.TAG_NAME }}"/g' ansible-webui/aw/config/hardcoded.py - - name: Building - run: python3 -m build + run: | + echo "${{ steps.version.outputs.TAG_NAME }}" > VERSION + python3 -m build shell: bash - name: Publish to PyPI diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 575d7b8..37c7dbc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -34,9 +34,9 @@ jobs: - name: Install dependencies run: | - pip install -r requirements_test.txt - pip install -r requirements_build.txt - pip install -r requirements.txt + pip install -r requirements_test.txt >/dev/null + pip install -r requirements_build.txt >/dev/null + pip install -r requirements.txt >/dev/null shell: bash - name: Testing DB migrations for errors & warnings @@ -46,12 +46,12 @@ jobs: m2=$(python3 manage.py migrate 2>&1) if echo "$m2" | grep -q 'WARNING'; then exit 1;fi shell: bash - working-directory: ansible-webui/ + working-directory: src/ansible-webui/ - name: Testing to start Ansible-WebUI run: | set +e - timeout 2 python3 ansible-webui + timeout 2 python3 src/ansible-webui ec="$?" if [[ "$ec" != "124" ]] then diff --git a/.gitignore b/.gitignore index c5c4ac1..877842d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ venv/ ansible_webui.egg-info/ __pychache__.py **/aw.db -**/aw.dev.db \ No newline at end of file +**/aw.dev.db +VERSION \ No newline at end of file diff --git a/.pylintrc b/.pylintrc index 0be883c..5a887fe 100644 --- a/.pylintrc +++ b/.pylintrc @@ -1,3 +1,6 @@ +[MASTER] +init-hook='import sys; sys.path.append("src/ansible-webui/")' + [MAIN] # Analyse import fallback blocks. This can be used to support both Python 2 and @@ -52,7 +55,8 @@ ignore=CVS # ignore-list. The regex matches against paths and can be in Posix or Windows # format. Because '\\' represents the directory delimiter on Windows systems, # it can't be used as an escape character. -ignore-paths=venv/* +ignore-paths=venv/*, + src/ansible-webui/aw/migrations/* # Files or directories matching the regular expression patterns are skipped. # The regex matches against base names, not paths. The default value ignores @@ -279,16 +283,17 @@ valid-metaclass-classmethod-first-arg=mcs # List of regular expressions of class ancestor names to ignore when counting # public methods (see R0903) exclude-too-few-public-methods= +# todo: exclude models # List of qualified class names to ignore when counting class parents (see # R0901) ignored-parents= # Maximum number of arguments for function / method. -max-args=5 +max-args=7 # Maximum number of attributes for a class (see R0902). -max-attributes=7 +max-attributes=10 # Maximum number of boolean expressions in an if statement (see R0916). max-bool-expr=5 @@ -424,6 +429,9 @@ confidence=HIGH, disable=C0114, C0115, C0116, # no inline docs C0103, # var-naming.. W0511, # todo comments + W0707, # has reasons + R0903, # todo: exclude models + E0401 # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option diff --git a/ansible-webui/aw/permission.py b/ansible-webui/aw/permission.py deleted file mode 100644 index 981d817..0000000 --- a/ansible-webui/aw/permission.py +++ /dev/null @@ -1,20 +0,0 @@ -from aw.config.hardcoded import PERMISSIONS - - -def _group_check(user, permission: str) -> bool: - if user and user.groups.filter(name=PERMISSIONS[permission]).exists(): - return True - - return False - - -# def authorized_to_access(user) -> bool: -# return _group_check(user, 'access') - - -def authorized_to_exec(user) -> bool: - return _group_check(user, 'exec') - - -def authorized_to_write(user) -> bool: - return _group_check(user, 'write') diff --git a/ansible-webui/main.py b/ansible-webui/main.py deleted file mode 100644 index 081d40c..0000000 --- a/ansible-webui/main.py +++ /dev/null @@ -1,56 +0,0 @@ -import signal -from os import getpid -from os import kill as os_kill -from time import sleep -from sys import exit as sys_exit -from threading import Thread -from platform import uname - -# pylint: disable=E0401,C0413 -from gunicorn.arbiter import Arbiter -from django import setup as django_setup - -from aw.config.main import init_globals - -init_globals() - -from base.webserver import init_webserver - - -def main(): - if uname().system.lower() != 'linux': - raise SystemError('Currently only linux systems are supported!') - - django_setup() - - init_scheduler() - init_webserver() - - -def init_scheduler(): - # pylint: disable=C0415 - from base.scheduler import Scheduler - scheduler = Scheduler() - scheduler_thread = Thread(target=scheduler.start) - - # override gunicorn signal handling to allow for graceful shutdown - Arbiter.SIGNALS.remove(signal.SIGHUP) - Arbiter.SIGNALS.remove(signal.SIGINT) - Arbiter.SIGNALS.remove(signal.SIGTERM) - - def signal_exit(signum=None, stack=None): - del stack - scheduler.stop(signum) - os_kill(getpid(), signal.SIGQUIT) # trigger 'Arbiter.stop' - sleep(3) - sys_exit(0) - - def signal_reload(signum=None, stack=None): - del stack - scheduler.reload(signum) - - signal.signal(signal.SIGHUP, signal_reload) - signal.signal(signal.SIGINT, signal_exit) - signal.signal(signal.SIGTERM, signal_exit) - - scheduler_thread.start() diff --git a/pyproject.toml b/pyproject.toml index f1bfca4..1dced2b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,30 @@ [build-system] -requires = ['setuptools>=42'] -build-backend = 'setuptools.build_meta' +requires = ["setuptools >= 61.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "ansible-webui" +authors = [ + {name = "AnsibleGuy", email = "contact@ansibleguy.net"}, +] +description = "Basic WebUI for using Ansible" +readme = "README.md" +requires-python = ">=3.5" +keywords = ["ansible", "webui", "automation", "iac"] +license = {file = "LICENSE.txt"} +classifiers = [ + 'Programming Language :: Python :: 3', + 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', + 'Framework :: Django', +] +dynamic = ["dependencies", "version"] + +[project.urls] +Homepage = "https://github.com/ansibleguy/ansible-webui" +Documentation = "https://ansible-webui.readthedocs.io/" +Repository = "https://github.com/ansibleguy/ansible-webui.git" +Issues = "https://github.com/ansibleguy/issues" + +[tool.setuptools.dynamic] +dependencies = {file = ["requirements.txt"]} +version = {file = ["VERSION"]} diff --git a/scripts/migrate_db.sh b/scripts/migrate_db.sh index d3b0148..53c8d9f 100644 --- a/scripts/migrate_db.sh +++ b/scripts/migrate_db.sh @@ -19,7 +19,7 @@ then git ls-files . --exclude-standard --others | grep 'migrations' | xargs --no-run-if-empty rm fi -cd "$(pwd)/ansible-webui/" +cd "$(pwd)/src/ansible-webui/" echo '' echo 'Creating migrations' diff --git a/scripts/run_pip_build.sh b/scripts/run_pip_build.sh index 51839f8..30098bb 100644 --- a/scripts/run_pip_build.sh +++ b/scripts/run_pip_build.sh @@ -23,12 +23,15 @@ echo '' echo 'Building & Installing Module using PIP' echo '' +bash ./scripts/update_version.sh + python3 -m pip install -e "$path_repo" >/dev/null echo '' echo 'Starting app' echo '' +cd /tmp python3 -m ansible-webui echo '' diff --git a/scripts/run_shared.sh b/scripts/run_shared.sh index e5b46d4..b6b744d 100644 --- a/scripts/run_shared.sh +++ b/scripts/run_shared.sh @@ -9,7 +9,7 @@ function log() { } cd "$(pwd)/.." -TEST_DB="$(pwd)/ansible-webui/aw.${AW_ENV}.db" +TEST_DB="$(pwd)/src/ansible-webui/aw.${AW_ENV}.db" TEST_MIGRATE='' if [ -f "$TEST_DB" ] && [[ "$TEST_QUIET" != "1" ]] @@ -38,11 +38,16 @@ then python3 -m pip install --upgrade -r ../requirements.txt >/dev/null fi +log 'SETTING VERSION' +bash ./scripts/update_version.sh +version="$(cat './VERSION')" +export AW_VERSION="$version" + log 'INITIALIZING DATABASE SCHEMA' bash ./scripts/migrate_db.sh "$TEST_MIGRATE" log 'CREATING USERS' -python3 ansible-webui/manage.py createsuperuser --noinput || true +python3 ./src/ansible-webui/manage.py createsuperuser --noinput || true log 'STARTING APP' -python3 ansible-webui +python3 ./src/ansible-webui diff --git a/scripts/update_version.sh b/scripts/update_version.sh new file mode 100644 index 0000000..4c81618 --- /dev/null +++ b/scripts/update_version.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +#last_tag="$(git describe --exact-match --abbrev=0)" +last_tag="0.0.1" +echo "${last_tag}.dev" > "$(dirname "$0")/../VERSION" diff --git a/setup.py b/setup.py deleted file mode 100644 index 3958585..0000000 --- a/setup.py +++ /dev/null @@ -1,29 +0,0 @@ -import setuptools - -with open('README.md', 'r', encoding='utf-8') as info: - long_description = info.read() - -with open('requirements.txt', 'r', encoding='utf-8') as reqs: - requirements = [req for req in reqs.readlines() if not req.startswith('#') or req.strip() == ''] - -setuptools.setup( - name='ansible-webui', - version='0.0.1', - author='AnsibleGuy', - author_email='contact@ansibleguy.net', - description='Basic WebUI for using Ansible', - long_description=long_description, - long_description_content_type='text/markdown', - url='https://github.com/ansibleguy/ansible-webui', - project_urls={ - 'Repository': 'https://github.com/ansibleguy/ansible-webui', - 'Bug Tracker': 'https://github.com/ansibleguy/ansible-webui/issues', - }, - classifiers=[ - 'Programming Language :: Python :: 3', - 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', - 'Operating System :: OS Independent', - ], - python_requires='>=3.5', - install_requires=requirements, -) diff --git a/ansible-webui/__init__.py b/src/ansible-webui/__init__.py similarity index 100% rename from ansible-webui/__init__.py rename to src/ansible-webui/__init__.py diff --git a/ansible-webui/__main__.py b/src/ansible-webui/__main__.py similarity index 86% rename from ansible-webui/__main__.py rename to src/ansible-webui/__main__.py index 02b0cf8..ab15a3b 100644 --- a/ansible-webui/__main__.py +++ b/src/ansible-webui/__main__.py @@ -14,11 +14,12 @@ sys_path.append(os_path.dirname(os_path.abspath(__file__))) from main import main - from aw.config.hardcoded import VERSION + from aw.config.main import VERSION if len(sys_argv) > 1: if sys_argv[1] == 'version': print(VERSION) sys_exit(0) + print(f'Ansible-WebUI Version {VERSION}') main() diff --git a/ansible-webui/aw/__init__.py b/src/ansible-webui/aw/__init__.py similarity index 100% rename from ansible-webui/aw/__init__.py rename to src/ansible-webui/aw/__init__.py diff --git a/ansible-webui/aw/admin.py b/src/ansible-webui/aw/admin.py similarity index 100% rename from ansible-webui/aw/admin.py rename to src/ansible-webui/aw/admin.py diff --git a/ansible-webui/aw/apps.py b/src/ansible-webui/aw/apps.py similarity index 100% rename from ansible-webui/aw/apps.py rename to src/ansible-webui/aw/apps.py diff --git a/ansible-webui/aw/config/__init__.py b/src/ansible-webui/aw/config/__init__.py similarity index 100% rename from ansible-webui/aw/config/__init__.py rename to src/ansible-webui/aw/config/__init__.py diff --git a/ansible-webui/aw/config/environment.py b/src/ansible-webui/aw/config/environment.py similarity index 100% rename from ansible-webui/aw/config/environment.py rename to src/ansible-webui/aw/config/environment.py diff --git a/ansible-webui/aw/config/hardcoded.py b/src/ansible-webui/aw/config/hardcoded.py similarity index 72% rename from ansible-webui/aw/config/hardcoded.py rename to src/ansible-webui/aw/config/hardcoded.py index 5daa823..d0b8856 100644 --- a/ansible-webui/aw/config/hardcoded.py +++ b/src/ansible-webui/aw/config/hardcoded.py @@ -1,5 +1,3 @@ -VERSION = "0.0.1" - ENV_KEY_DEPLOYMENT = 'AW_ENV' ENV_KEY_SERVE_STATIC = 'AW_STATIC' ENV_KEY_DB = 'AW_DB' @@ -11,9 +9,3 @@ LOGOUT_PATH = '/o/' LOG_TIME_FORMAT = '%Y-%m-%d %H:%M:%S %z' RUNNER_TMP_DIR_TIME_FORMAT = '%Y-%m-%d_%H-%M-%S' - -PERMISSIONS = dict( - access='AW_ACCESS', - write='AW_WRITE', - exec='AW_EXEC', -) diff --git a/ansible-webui/aw/config/main.py b/src/ansible-webui/aw/config/main.py similarity index 80% rename from ansible-webui/aw/config/main.py rename to src/ansible-webui/aw/config/main.py index 46d45e8..cf4890b 100644 --- a/ansible-webui/aw/config/main.py +++ b/src/ansible-webui/aw/config/main.py @@ -1,11 +1,16 @@ from os import environ +from importlib.metadata import version from pytz import all_timezones from aw.config.environment import ENVIRON_FALLBACK +VERSION = environ['AW_VERSION'] if 'AW_VERSION' in environ else version('ansible-webui') + + def init_globals(): + # pylint: disable=W0601 global config config = {} diff --git a/ansible-webui/aw/config/navigation.py b/src/ansible-webui/aw/config/navigation.py similarity index 93% rename from ansible-webui/aw/config/navigation.py rename to src/ansible-webui/aw/config/navigation.py index 89ecf91..c14f5a9 100644 --- a/ansible-webui/aw/config/navigation.py +++ b/src/ansible-webui/aw/config/navigation.py @@ -34,7 +34,8 @@ 'login': False, }, 'LO': { - 'element': '', + 'element': '', 'url': LOGOUT_PATH, 'login': True, }, diff --git a/ansible-webui/aw/execute/__init__.py b/src/ansible-webui/aw/execute/__init__.py similarity index 100% rename from ansible-webui/aw/execute/__init__.py rename to src/ansible-webui/aw/execute/__init__.py diff --git a/ansible-webui/aw/execute/play.py b/src/ansible-webui/aw/execute/play.py similarity index 100% rename from ansible-webui/aw/execute/play.py rename to src/ansible-webui/aw/execute/play.py diff --git a/ansible-webui/aw/execute/util.py b/src/ansible-webui/aw/execute/util.py similarity index 98% rename from ansible-webui/aw/execute/util.py rename to src/ansible-webui/aw/execute/util.py index 45f31ce..f68ab1d 100644 --- a/ansible-webui/aw/execute/util.py +++ b/src/ansible-webui/aw/execute/util.py @@ -74,7 +74,7 @@ def _runner_options(job: Job, execution: JobExecution) -> dict: } -def runner_prep(job: Job, execution: (JobExecution, None)): +def runner_prep(job: Job, execution: (JobExecution, None)) -> dict: if execution is None: execution = JobExecution(user=None, job=job, comment='Scheduled') @@ -106,6 +106,8 @@ def runner_prep(job: Job, execution: (JobExecution, None)): _update_execution_status(execution, status='Running') + return opts + def runner_cleanup(opts: dict): rmtree(opts['private_data_dir']) diff --git a/ansible-webui/aw/main.py b/src/ansible-webui/aw/main.py similarity index 100% rename from ansible-webui/aw/main.py rename to src/ansible-webui/aw/main.py diff --git a/ansible-webui/aw/migrations/__init__.py b/src/ansible-webui/aw/migrations/__init__.py similarity index 100% rename from ansible-webui/aw/migrations/__init__.py rename to src/ansible-webui/aw/migrations/__init__.py diff --git a/ansible-webui/aw/model/__init__.py b/src/ansible-webui/aw/model/__init__.py similarity index 100% rename from ansible-webui/aw/model/__init__.py rename to src/ansible-webui/aw/model/__init__.py diff --git a/ansible-webui/aw/model/base.py b/src/ansible-webui/aw/model/base.py similarity index 100% rename from ansible-webui/aw/model/base.py rename to src/ansible-webui/aw/model/base.py diff --git a/ansible-webui/aw/model/job.py b/src/ansible-webui/aw/model/job.py similarity index 96% rename from ansible-webui/aw/model/job.py rename to src/ansible-webui/aw/model/job.py index a71ff0e..4843c59 100644 --- a/ansible-webui/aw/model/job.py +++ b/src/ansible-webui/aw/model/job.py @@ -101,8 +101,8 @@ class JobExecutionResultHost(BareModel): tasks_ignored = models.PositiveSmallIntegerField(default=0) tasks_changed = models.PositiveSmallIntegerField(default=0) - error = models.ForeignKey(JobError, on_delete=models.CASCADE, related_name=f"jobresulthost_fk_error") - result = models.ForeignKey(JobExecutionResult, on_delete=models.CASCADE, related_name=f"jobresulthost_fk_result") + error = models.ForeignKey(JobError, on_delete=models.CASCADE, related_name='jobresulthost_fk_error') + result = models.ForeignKey(JobExecutionResult, on_delete=models.CASCADE, related_name='jobresulthost_fk_result') def __str__(self) -> str: if int(self.tasks_failed) > 0: @@ -126,11 +126,11 @@ class JobExecution(MetaJob): # NOTE: scheduled execution will have no user user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.PROTECT, null=True, - related_name=f"jobexec_fk_user" + related_name='jobexec_fk_user' ) - job = models.ForeignKey(Job, on_delete=models.CASCADE, related_name=f"jobexec_fk_job") + job = models.ForeignKey(Job, on_delete=models.CASCADE, related_name='jobexec_fk_job') result = models.ForeignKey( - JobExecutionResult, on_delete=models.CASCADE, related_name=f"jobexec_fk_result", + JobExecutionResult, on_delete=models.CASCADE, related_name='jobexec_fk_result', null=True, default=None, # execution is created before result is available ) status = models.PositiveSmallIntegerField(default=0, choices=CHOICES_JOB_EXEC_STATUS) diff --git a/ansible-webui/aw/models.py b/src/ansible-webui/aw/models.py similarity index 85% rename from ansible-webui/aw/models.py rename to src/ansible-webui/aw/models.py index fac465c..651182d 100644 --- a/ansible-webui/aw/models.py +++ b/src/ansible-webui/aw/models.py @@ -1,2 +1,3 @@ +# pylint: disable=W0611 from aw.model.job import JobError, JobExecution, Job, JobPermission, JobPermissionMemberGroup, \ JobPermissionMemberUser, JobExecutionResult diff --git a/ansible-webui/aw/route.py b/src/ansible-webui/aw/route.py similarity index 84% rename from ansible-webui/aw/route.py rename to src/ansible-webui/aw/route.py index d324a21..54e714c 100644 --- a/ansible-webui/aw/route.py +++ b/src/ansible-webui/aw/route.py @@ -1,10 +1,9 @@ -from django.contrib.auth.decorators import login_required, user_passes_test +from django.contrib.auth.decorators import login_required # user_passes_test from django.shortcuts import HttpResponse, redirect, render from django.conf import settings from django.contrib.auth.views import logout_then_login from aw.config.hardcoded import LOGIN_PATH -from aw.permission import authorized_to_exec, authorized_to_write def _deny(request) -> (bool, HttpResponse): @@ -16,6 +15,7 @@ def _deny(request) -> (bool, HttpResponse): @login_required def ui(request, **kwargs): + del kwargs bad, deny = _deny(request) if bad: return deny @@ -29,20 +29,23 @@ def ui(request, **kwargs): return render(request, status=200, template_name='fallback.html', context={'content': 'OK - read'}) +# @user_passes_test(authorized_to_write, login_url=LOGIN_PATH) @login_required -@user_passes_test(authorized_to_write, login_url=LOGIN_PATH) def ui_write(request, **kwargs): + del kwargs return render(request, status=200, template_name='fallback.html', context={'content': 'OK - write'}) +# @user_passes_test(authorized_to_exec, login_url=LOGIN_PATH) @login_required -@user_passes_test(authorized_to_exec, login_url=LOGIN_PATH) def ui_exec(request, **kwargs): + del kwargs return render(request, status=200, template_name='fallback.html', context={'content': 'OK - exec'}) @login_required def manage(request, **kwargs): + del kwargs return render(request, status=200, template_name='fallback.html', context={ 'content': '' @@ -50,10 +53,12 @@ def manage(request, **kwargs): def not_implemented(request, **kwargs): + del kwargs return render(request, status=404, template_name='fallback.html', context={'content': 'Not yet implemented'}) def catchall(request, **kwargs): + del kwargs if request.user.is_authenticated: return redirect(settings.LOGIN_REDIRECT_URL) @@ -61,4 +66,5 @@ def catchall(request, **kwargs): def logout(request, **kwargs): + del kwargs return logout_then_login(request) diff --git a/ansible-webui/aw/settings.py b/src/ansible-webui/aw/settings.py similarity index 98% rename from ansible-webui/aw/settings.py rename to src/ansible-webui/aw/settings.py index d580eae..748de3e 100644 --- a/ansible-webui/aw/settings.py +++ b/src/ansible-webui/aw/settings.py @@ -1,13 +1,11 @@ from pathlib import Path from os import environ -# Build paths inside the project like this: BASE_DIR / 'subdir'. -BASE_DIR = Path(__file__).resolve().parent.parent - from aw.config.main import config from aw.config.hardcoded import LOGIN_PATH, ENV_KEY_DB from aw.utils.deployment import deployment_dev, deployment_prod +BASE_DIR = Path(__file__).resolve().parent.parent DEBUG = deployment_dev() ALLOWED_HOSTS = ['*'] diff --git a/ansible-webui/aw/static/css/aw.css b/src/ansible-webui/aw/static/css/aw.css similarity index 100% rename from ansible-webui/aw/static/css/aw.css rename to src/ansible-webui/aw/static/css/aw.css diff --git a/ansible-webui/aw/static/css/aw_mobile.css b/src/ansible-webui/aw/static/css/aw_mobile.css similarity index 100% rename from ansible-webui/aw/static/css/aw_mobile.css rename to src/ansible-webui/aw/static/css/aw_mobile.css diff --git a/ansible-webui/aw/templates/body.html b/src/ansible-webui/aw/templates/body.html similarity index 100% rename from ansible-webui/aw/templates/body.html rename to src/ansible-webui/aw/templates/body.html diff --git a/ansible-webui/aw/templates/error/403.html b/src/ansible-webui/aw/templates/error/403.html similarity index 100% rename from ansible-webui/aw/templates/error/403.html rename to src/ansible-webui/aw/templates/error/403.html diff --git a/ansible-webui/aw/templates/error/500.html b/src/ansible-webui/aw/templates/error/500.html similarity index 100% rename from ansible-webui/aw/templates/error/500.html rename to src/ansible-webui/aw/templates/error/500.html diff --git a/ansible-webui/aw/templates/error/js_disabled.html b/src/ansible-webui/aw/templates/error/js_disabled.html similarity index 100% rename from ansible-webui/aw/templates/error/js_disabled.html rename to src/ansible-webui/aw/templates/error/js_disabled.html diff --git a/ansible-webui/aw/templates/fallback.html b/src/ansible-webui/aw/templates/fallback.html similarity index 100% rename from ansible-webui/aw/templates/fallback.html rename to src/ansible-webui/aw/templates/fallback.html diff --git a/ansible-webui/aw/templates/head.html b/src/ansible-webui/aw/templates/head.html similarity index 100% rename from ansible-webui/aw/templates/head.html rename to src/ansible-webui/aw/templates/head.html diff --git a/ansible-webui/aw/templates/nav.html b/src/ansible-webui/aw/templates/nav.html similarity index 100% rename from ansible-webui/aw/templates/nav.html rename to src/ansible-webui/aw/templates/nav.html diff --git a/ansible-webui/aw/templates/registration/login.html b/src/ansible-webui/aw/templates/registration/login.html similarity index 100% rename from ansible-webui/aw/templates/registration/login.html rename to src/ansible-webui/aw/templates/registration/login.html diff --git a/ansible-webui/aw/templatetags/__init__.py b/src/ansible-webui/aw/templatetags/__init__.py similarity index 100% rename from ansible-webui/aw/templatetags/__init__.py rename to src/ansible-webui/aw/templatetags/__init__.py diff --git a/ansible-webui/aw/templatetags/util.py b/src/ansible-webui/aw/templatetags/util.py similarity index 93% rename from ansible-webui/aw/templatetags/util.py rename to src/ansible-webui/aw/templatetags/util.py index 44f1d5b..bef2202 100644 --- a/ansible-webui/aw/templatetags/util.py +++ b/src/ansible-webui/aw/templatetags/util.py @@ -1,6 +1,6 @@ from django import template -from aw.config.hardcoded import VERSION +from aw.config.main import VERSION from aw.config.navigation import NAVIGATION diff --git a/ansible-webui/aw/utils/__init__.py b/src/ansible-webui/aw/utils/__init__.py similarity index 100% rename from ansible-webui/aw/utils/__init__.py rename to src/ansible-webui/aw/utils/__init__.py diff --git a/ansible-webui/aw/utils/debug.py b/src/ansible-webui/aw/utils/debug.py similarity index 100% rename from ansible-webui/aw/utils/debug.py rename to src/ansible-webui/aw/utils/debug.py diff --git a/ansible-webui/aw/utils/deployment.py b/src/ansible-webui/aw/utils/deployment.py similarity index 100% rename from ansible-webui/aw/utils/deployment.py rename to src/ansible-webui/aw/utils/deployment.py diff --git a/ansible-webui/aw/utils/handlers.py b/src/ansible-webui/aw/utils/handlers.py similarity index 100% rename from ansible-webui/aw/utils/handlers.py rename to src/ansible-webui/aw/utils/handlers.py diff --git a/ansible-webui/aw/utils/util.py b/src/ansible-webui/aw/utils/util.py similarity index 94% rename from ansible-webui/aw/utils/util.py rename to src/ansible-webui/aw/utils/util.py index 1ba9dee..35ed0d0 100644 --- a/ansible-webui/aw/utils/util.py +++ b/src/ansible-webui/aw/utils/util.py @@ -13,3 +13,5 @@ def get_choice_key_by_value(choices: list[tuple], value): for k, v in choices: if v == value: return k + + return None diff --git a/ansible-webui/aw/utils/util_test.py b/src/ansible-webui/aw/utils/util_test.py similarity index 100% rename from ansible-webui/aw/utils/util_test.py rename to src/ansible-webui/aw/utils/util_test.py diff --git a/ansible-webui/base/__init__.py b/src/ansible-webui/base/__init__.py similarity index 100% rename from ansible-webui/base/__init__.py rename to src/ansible-webui/base/__init__.py diff --git a/ansible-webui/base/scheduler.py b/src/ansible-webui/base/scheduler.py similarity index 64% rename from ansible-webui/base/scheduler.py rename to src/ansible-webui/base/scheduler.py index 025c6aa..7cb27b0 100644 --- a/ansible-webui/base/scheduler.py +++ b/src/ansible-webui/base/scheduler.py @@ -1,5 +1,12 @@ +import signal +from os import getpid +from os import kill as os_kill +from sys import exit as sys_exit +from threading import Thread from time import sleep, time +from gunicorn.arbiter import Arbiter + from base.threader import ThreadManager from aw.utils.debug import log from aw.config.hardcoded import RELOAD_INTERVAL @@ -45,8 +52,8 @@ def _signum_log(signum): def _thread(self, job: Job, execution: JobExecution = None): # todo: creation of execution object for ad-hoc execution (with user-provided values) - self.thread_manager.add_thread(job) - self.thread_manager.start_thread(job) + self.thread_manager.add_thread(job=job, execution=execution) + self.thread_manager.start_thread(job=job) def start(self): log('Starting..', level=3) @@ -57,6 +64,7 @@ def start(self): self._run() def _run(self): + # pylint: disable=W0718 try: sleep(self.WAIT_TIME) log('Entering Scheduler runtime', level=7) @@ -76,3 +84,30 @@ def _run(self): print(f'ERROR: {err}') self.stop() return + + +def init_scheduler(): + scheduler = Scheduler() + scheduler_thread = Thread(target=scheduler.start) + + # override gunicorn signal handling to allow for graceful shutdown + Arbiter.SIGNALS.remove(signal.SIGHUP) + Arbiter.SIGNALS.remove(signal.SIGINT) + Arbiter.SIGNALS.remove(signal.SIGTERM) + + def signal_exit(signum=None, stack=None): + del stack + scheduler.stop(signum) + os_kill(getpid(), signal.SIGQUIT) # trigger 'Arbiter.stop' + sleep(3) + sys_exit(0) + + def signal_reload(signum=None, stack=None): + del stack + scheduler.reload(signum) + + signal.signal(signal.SIGHUP, signal_reload) + signal.signal(signal.SIGINT, signal_exit) + signal.signal(signal.SIGTERM, signal_exit) + + scheduler_thread.start() diff --git a/ansible-webui/base/serve_static.py b/src/ansible-webui/base/serve_static.py similarity index 92% rename from ansible-webui/base/serve_static.py rename to src/ansible-webui/base/serve_static.py index a929d93..b85e172 100644 --- a/ansible-webui/base/serve_static.py +++ b/src/ansible-webui/base/serve_static.py @@ -22,12 +22,13 @@ def serve(request, path, **kwargs): if not absolute_path: if path.endswith("/") or path == "": raise Http404('Directory indexes are not allowed here.') - raise Http404("'%s' could not be found" % path) + raise Http404(f"'{path}' could not be found") document_root, path = os_path.split(absolute_path) return static.serve(request, path, document_root=document_root, **kwargs) +# pylint: disable=C0209 urlpatterns_static = [re_path( r"^%s(?P.*)$" % regex_escape(settings.STATIC_URL.lstrip('/')), serve, )] diff --git a/ansible-webui/base/threader.py b/src/ansible-webui/base/threader.py similarity index 89% rename from ansible-webui/base/threader.py rename to src/ansible-webui/base/threader.py index 04c613e..b666cdb 100644 --- a/ansible-webui/base/threader.py +++ b/src/ansible-webui/base/threader.py @@ -52,17 +52,15 @@ def run(self) -> None: self.manager.threads.remove(self.job) return - else: - wait_sec = self.cron.next() - log(f"Next execution of job {self.log_name} in {wait_sec}s", level=7) - while not self.state_stop.wait(wait_sec): - if self.state_stop.is_set(): - log(f"Exiting thread {self.log_name}", level=5) - break - - else: - log(f"Starting job {self.log_name}", level=5) - self.run_playbook() + wait_sec = self.cron.next() + log(f"Next execution of job {self.log_name} in {wait_sec}s", level=7) + while not self.state_stop.wait(wait_sec): + if self.state_stop.is_set(): + log(f"Exiting thread {self.log_name}", level=5) + break + + log(f"Starting job {self.log_name}", level=5) + self.run_playbook() except ValueError as err: log(f"Got unexpected error while executing job {self.log_name}: '{err}'") diff --git a/ansible-webui/base/webserver.py b/src/ansible-webui/base/webserver.py similarity index 91% rename from ansible-webui/base/webserver.py rename to src/ansible-webui/base/webserver.py index 5516ee2..2034676 100644 --- a/ansible-webui/base/webserver.py +++ b/src/ansible-webui/base/webserver.py @@ -39,15 +39,17 @@ def load_config(self): def init_webserver(): gunicorn.SERVER = ''.join(random_choice(ascii_letters) for _ in range(10)) - run_options = { + opts = { 'workers': (cpu_count() * 2) + 1, **OPTIONS_PROD } if deployment_dev(): warn_if_development() - run_options = {**run_options, **OPTIONS_DEV} + opts = {**opts, **OPTIONS_DEV} + + print(f"Listening on http://{opts['bind']}") StandaloneApplication( app_uri="aw.main:app", - options=run_options + options=opts ).run() diff --git a/src/ansible-webui/main.py b/src/ansible-webui/main.py new file mode 100644 index 0000000..6b1ecb9 --- /dev/null +++ b/src/ansible-webui/main.py @@ -0,0 +1,21 @@ +from platform import uname + +from django import setup as django_setup + +from aw.config.main import init_globals + +init_globals() + + +def main(): + if uname().system.lower() != 'linux': + raise SystemError('Currently only linux systems are supported!') + + django_setup() + + # pylint: disable=C0415 + from base.webserver import init_webserver + from base.scheduler import init_scheduler + + init_scheduler() + init_webserver() diff --git a/ansible-webui/manage.py b/src/ansible-webui/manage.py similarity index 100% rename from ansible-webui/manage.py rename to src/ansible-webui/manage.py diff --git a/ansible-webui/route.py b/src/ansible-webui/route.py similarity index 100% rename from ansible-webui/route.py rename to src/ansible-webui/route.py