mirror of
https://github.com/MOIS3Y/logs-collector.git
synced 2025-02-01 01:10:52 +01:00
Modify: settings - add DATA_DIR logs_collector storage_info use DATA_DIR as storage root
This commit is contained in:
parent
5893920d69
commit
57a758f93e
10
Dockerfile
10
Dockerfile
@ -22,6 +22,7 @@ ENV PYTHONUNBUFFERED 1
|
|||||||
# default build args
|
# default build args
|
||||||
ARG VERSION=0.1.0 \
|
ARG VERSION=0.1.0 \
|
||||||
APP_DIR=/app \
|
APP_DIR=/app \
|
||||||
|
DATA_DIR=/app/data \
|
||||||
SRC_DIR=./logs_collector \
|
SRC_DIR=./logs_collector \
|
||||||
SCRIPTS_DIR=./scripts \
|
SCRIPTS_DIR=./scripts \
|
||||||
WEB_PORT=8000 \
|
WEB_PORT=8000 \
|
||||||
@ -34,17 +35,20 @@ ARG VERSION=0.1.0 \
|
|||||||
COPY --from=base /usr/local/lib/python3.10/site-packages/ /usr/local/lib/python3.10/site-packages/
|
COPY --from=base /usr/local/lib/python3.10/site-packages/ /usr/local/lib/python3.10/site-packages/
|
||||||
COPY --from=base /usr/local/bin/ /usr/local/bin/
|
COPY --from=base /usr/local/bin/ /usr/local/bin/
|
||||||
|
|
||||||
# add curl and createa user to avoid running container as root
|
# add curl and createa user to avoid running container as root &&
|
||||||
|
# create storage dir
|
||||||
RUN apk add --no-cache --upgrade curl && \
|
RUN apk add --no-cache --upgrade curl && \
|
||||||
addgroup --system ${USER_GROUP} --gid ${APP_GID} && \
|
addgroup --system ${USER_GROUP} --gid ${APP_GID} && \
|
||||||
adduser --system --uid ${APP_UID} --ingroup ${USER_GROUP} ${USER_NAME}
|
adduser --system --uid ${APP_UID} --ingroup ${USER_GROUP} ${USER_NAME} && \
|
||||||
|
mkdir -p ${APP_DIR}/data && \
|
||||||
|
chown -R ${USER_NAME}:${USER_GROUP} ${DATA_DIR}
|
||||||
|
|
||||||
# switch to user
|
# switch to user
|
||||||
USER ${USER_NAME}
|
USER ${USER_NAME}
|
||||||
|
|
||||||
# copy src and entrypoint.sh to app dir
|
# copy src and entrypoint.sh to app dir
|
||||||
COPY --chown=${USER_NAME}:${USER_GROUP} ${SRC_DIR} ${APP_DIR}
|
COPY --chown=${USER_NAME}:${USER_GROUP} ${SRC_DIR} ${APP_DIR}
|
||||||
COPY --chown=${USER_NAME}:${USER_GROUP} ${SCRIPTS_DIR}/entrypoint.sh ${APP_DIR}/
|
COPY --chown=${USER_NAME}:${USER_GROUP} ${SCRIPTS_DIR}/entrypoint.sh ${APP_DIR}
|
||||||
|
|
||||||
# set workdir
|
# set workdir
|
||||||
WORKDIR ${APP_DIR}
|
WORKDIR ${APP_DIR}
|
||||||
|
@ -13,6 +13,7 @@ services:
|
|||||||
- SRC_DIR=${SRC_DIR}
|
- SRC_DIR=${SRC_DIR}
|
||||||
- SCRIPTS_DIR=${SCRIPTS_DIR}
|
- SCRIPTS_DIR=${SCRIPTS_DIR}
|
||||||
- APP_DIR=${APP_DIR}
|
- APP_DIR=${APP_DIR}
|
||||||
|
- DATA_DIR=${DATA_DIR}
|
||||||
- WEB_PORT=${WEB_PORT}
|
- WEB_PORT=${WEB_PORT}
|
||||||
- USER_NAME=${USER_NAME}
|
- USER_NAME=${USER_NAME}
|
||||||
- USER_GROUP=${USER_GROUP}
|
- USER_GROUP=${USER_GROUP}
|
||||||
|
@ -66,3 +66,4 @@ class StorageInfoSerializer(serializers.Serializer):
|
|||||||
used = serializers.IntegerField(read_only=True)
|
used = serializers.IntegerField(read_only=True)
|
||||||
free = serializers.IntegerField(read_only=True)
|
free = serializers.IntegerField(read_only=True)
|
||||||
used_percent = serializers.IntegerField(read_only=True)
|
used_percent = serializers.IntegerField(read_only=True)
|
||||||
|
status = serializers.CharField(read_only=True)
|
||||||
|
@ -171,4 +171,4 @@ class StorageInfo(views.APIView):
|
|||||||
summary='Show storage space in bytes'
|
summary='Show storage space in bytes'
|
||||||
)
|
)
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
return Response(get_mount_fs_info(settings.MEDIA_ROOT))
|
return Response(get_mount_fs_info(settings.DATA_DIR))
|
||||||
|
@ -13,4 +13,4 @@ def metadata(request):
|
|||||||
|
|
||||||
|
|
||||||
def storage_info(request):
|
def storage_info(request):
|
||||||
return {'storage': get_mount_fs_info(settings.MEDIA_ROOT)}
|
return {'storage': get_mount_fs_info(settings.DATA_DIR)}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import shutil
|
import shutil
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
|
||||||
def logs_dir_path(instance, filename):
|
def logs_dir_path(instance, filename: str) -> str:
|
||||||
"""
|
"""
|
||||||
file will be uploaded to
|
file will be uploaded to
|
||||||
MEDIA_ROOT/view/<filename>
|
MEDIA_ROOT/view/<filename>
|
||||||
@ -30,9 +31,31 @@ def sizify(value: int) -> str:
|
|||||||
return f'{round(value, 1)} {ext}'
|
return f'{round(value, 1)} {ext}'
|
||||||
|
|
||||||
|
|
||||||
def get_mount_fs_info(path):
|
def get_mount_fs_info(path: type[pathlib.PosixPath]) -> dict:
|
||||||
mount_info = shutil.disk_usage(path)._asdict()
|
"""
|
||||||
mount_info['used_percent'] = round(
|
Get directory information for storing uploaded files.
|
||||||
mount_info['used'] / mount_info['total'] * 100
|
Includes information total/used/free space on mount device
|
||||||
)
|
|
||||||
|
Args:
|
||||||
|
path (pathlib.PosixPath): path to storage dir
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: storage mount info
|
||||||
|
"""
|
||||||
|
mount_info: dict = {}
|
||||||
|
try:
|
||||||
|
mount_info = shutil.disk_usage(path)._asdict()
|
||||||
|
mount_info['used_percent'] = round(
|
||||||
|
mount_info['used'] / mount_info['total'] * 100,
|
||||||
|
)
|
||||||
|
mount_info['status'] = 'mount'
|
||||||
|
except Exception as error: # expected FileNotFoundError
|
||||||
|
mount_info = {
|
||||||
|
'total': 0,
|
||||||
|
'used': 0,
|
||||||
|
'free': 0,
|
||||||
|
'used_percent': 0,
|
||||||
|
'status': 'error',
|
||||||
|
'traceback': f'{error}'
|
||||||
|
}
|
||||||
return mount_info
|
return mount_info
|
||||||
|
@ -4,9 +4,19 @@ from datetime import timedelta
|
|||||||
|
|
||||||
from . import __version__, __status__
|
from . import __version__, __status__
|
||||||
|
|
||||||
|
|
||||||
|
# █▀█ █▀█ █▀█ ▀█▀ ▀
|
||||||
|
# █▀▄ █▄█ █▄█ ░█░ ▄
|
||||||
|
# -- -- -- -- -- --
|
||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
|
||||||
|
# █▀▀ █▄░█ █░█ ▀
|
||||||
|
# ██▄ █░▀█ ▀▄▀ ▄
|
||||||
|
# -- -- -- -- --
|
||||||
|
|
||||||
# Set default environ variables:
|
# Set default environ variables:
|
||||||
env = environ.Env(
|
env = environ.Env(
|
||||||
# set casting default value
|
# set casting default value
|
||||||
@ -14,7 +24,7 @@ env = environ.Env(
|
|||||||
ENVIRONMENT=(str, __status__),
|
ENVIRONMENT=(str, __status__),
|
||||||
DEBUG=(bool, False),
|
DEBUG=(bool, False),
|
||||||
SECRET_KEY=(str, 'j9QGbvM9Z4otb47'),
|
SECRET_KEY=(str, 'j9QGbvM9Z4otb47'),
|
||||||
SQLITE_URL=(str, f'sqlite:///{BASE_DIR / "data/db.sqlite3"}'),
|
DATA_DIR=(str, BASE_DIR / 'data'),
|
||||||
CSRF_TRUSTED_ORIGINS=(list, []),
|
CSRF_TRUSTED_ORIGINS=(list, []),
|
||||||
ALLOWED_HOSTS=(list, ['*']),
|
ALLOWED_HOSTS=(list, ['*']),
|
||||||
TZ=(str, 'UTC'),
|
TZ=(str, 'UTC'),
|
||||||
@ -23,7 +33,13 @@ env = environ.Env(
|
|||||||
# Read .env file if exist:
|
# Read .env file if exist:
|
||||||
environ.Env.read_env(BASE_DIR / '.env')
|
environ.Env.read_env(BASE_DIR / '.env')
|
||||||
|
|
||||||
|
|
||||||
|
# █▀▀ █▀█ █▀█ █▀▀ ▀
|
||||||
|
# █▄▄ █▄█ █▀▄ ██▄ ▄
|
||||||
|
# -- -- -- -- -- -
|
||||||
|
|
||||||
VERSION = env('VERSION')
|
VERSION = env('VERSION')
|
||||||
|
|
||||||
ENVIRONMENT = env('ENVIRONMENT')
|
ENVIRONMENT = env('ENVIRONMENT')
|
||||||
|
|
||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
@ -99,12 +115,6 @@ TEMPLATES = [
|
|||||||
|
|
||||||
WSGI_APPLICATION = 'logs_collector.wsgi.application'
|
WSGI_APPLICATION = 'logs_collector.wsgi.application'
|
||||||
|
|
||||||
# Database
|
|
||||||
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
|
|
||||||
DATABASES = {
|
|
||||||
'default': env.db_url('SQLITE_URL')
|
|
||||||
}
|
|
||||||
|
|
||||||
# Password validation
|
# Password validation
|
||||||
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
|
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
|
||||||
|
|
||||||
@ -134,6 +144,11 @@ USE_I18N = True
|
|||||||
|
|
||||||
USE_TZ = True
|
USE_TZ = True
|
||||||
|
|
||||||
|
|
||||||
|
# █▀ ▀█▀ ▄▀█ ▀█▀ █ █▀▀ ▀
|
||||||
|
# ▄█ ░█░ █▀█ ░█░ █ █▄▄ ▄
|
||||||
|
# -- -- -- -- -- -- -- -
|
||||||
|
|
||||||
# Static files (CSS, JavaScript, Images)
|
# Static files (CSS, JavaScript, Images)
|
||||||
# https://docs.djangoproject.com/en/4.2/howto/static-files/
|
# https://docs.djangoproject.com/en/4.2/howto/static-files/
|
||||||
# Whitenoise:
|
# Whitenoise:
|
||||||
@ -141,12 +156,19 @@ USE_TZ = True
|
|||||||
STATIC_URL = 'static/'
|
STATIC_URL = 'static/'
|
||||||
STATIC_ROOT = BASE_DIR / 'static'
|
STATIC_ROOT = BASE_DIR / 'static'
|
||||||
|
|
||||||
# Default primary key field type
|
|
||||||
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
|
|
||||||
|
|
||||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
# █▀▄ ▄▀█ ▀█▀ ▄▀█ ▀
|
||||||
|
# █▄▀ █▀█ ░█░ █▀█ ▄
|
||||||
|
# -- -- -- -- -- --
|
||||||
|
|
||||||
MEDIA_ROOT = BASE_DIR / 'data/archives'
|
# Build paths inside the project for db and storage.
|
||||||
|
DATA_DIR = Path(env('DATA_DIR'))
|
||||||
|
|
||||||
|
# Create DATA_DIR ignore if exist:
|
||||||
|
Path(DATA_DIR).mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# Custom file storage path
|
||||||
|
MEDIA_ROOT = DATA_DIR / 'archives'
|
||||||
|
|
||||||
STORAGES = {
|
STORAGES = {
|
||||||
"default": {
|
"default": {
|
||||||
@ -161,6 +183,29 @@ STORAGES = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# █▀▄ ▄▀█ ▀█▀ ▄▀█ █▄▄ ▄▀█ █▀ █▀▀ ▀
|
||||||
|
# █▄▀ █▀█ ░█░ █▀█ █▄█ █▀█ ▄█ ██▄ ▄
|
||||||
|
# -- -- -- -- -- -- -- -- -- -- --
|
||||||
|
|
||||||
|
# Database
|
||||||
|
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
|
||||||
|
DATABASES = {
|
||||||
|
'default': env.db_url(
|
||||||
|
'DB_URL',
|
||||||
|
default=f'sqlite:///{DATA_DIR / "db.sqlite3"}'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Default primary key field type
|
||||||
|
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
|
||||||
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||||
|
|
||||||
|
|
||||||
|
# █▀▀ ▀▄▀ ▀█▀ █▀▀ █▄░█ ▀█▀ █ █▀█ █▄░█ █▀ ▀
|
||||||
|
# ██▄ █░█ ░█░ ██▄ █░▀█ ░█░ █ █▄█ █░▀█ ▄█ ▄
|
||||||
|
# -- -- -- -- -- -- -- -- -- -- -- -- -- -
|
||||||
|
|
||||||
# django-crispy-forms and crispy-bootstrap5
|
# django-crispy-forms and crispy-bootstrap5
|
||||||
# https://django-crispy-forms.readthedocs.io/en/latest/
|
# https://django-crispy-forms.readthedocs.io/en/latest/
|
||||||
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
|
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
|
||||||
@ -196,7 +241,6 @@ if DEBUG:
|
|||||||
).append('rest_framework.renderers.BrowsableAPIRenderer')
|
).append('rest_framework.renderers.BrowsableAPIRenderer')
|
||||||
|
|
||||||
# https://drf-spectacular.readthedocs.io/en/latest/readme.html
|
# https://drf-spectacular.readthedocs.io/en/latest/readme.html
|
||||||
# TODO: set environ vars config!
|
|
||||||
SPECTACULAR_SETTINGS = {
|
SPECTACULAR_SETTINGS = {
|
||||||
'TITLE': 'Logs collector API',
|
'TITLE': 'Logs collector API',
|
||||||
'DESCRIPTION': 'Collector of archives with log files for further analysis',
|
'DESCRIPTION': 'Collector of archives with log files for further analysis',
|
||||||
@ -249,6 +293,11 @@ SIMPLE_JWT = {
|
|||||||
"SLIDING_TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSlidingSerializer", # noqa:E501
|
"SLIDING_TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSlidingSerializer", # noqa:E501
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ▄▀█ █░█ ▀█▀ █░█ ▀
|
||||||
|
# █▀█ █▄█ ░█░ █▀█ ▄
|
||||||
|
# -- -- -- -- -- --
|
||||||
|
|
||||||
LOGIN_URL = 'two_factor:login'
|
LOGIN_URL = 'two_factor:login'
|
||||||
LOGIN_REDIRECT_URL = 'collector:index'
|
LOGIN_REDIRECT_URL = 'collector:index'
|
||||||
LOGOUT_REDIRECT_URL = 'two_factor:login'
|
LOGOUT_REDIRECT_URL = 'two_factor:login'
|
||||||
|
@ -5,8 +5,18 @@
|
|||||||
class="nav-link me-1 bi bi-sd-card"
|
class="nav-link me-1 bi bi-sd-card"
|
||||||
aria-current="page"
|
aria-current="page"
|
||||||
data-bs-toggle="tooltip"
|
data-bs-toggle="tooltip"
|
||||||
|
data-bs-html="true"
|
||||||
data-bs-placement="bottom"
|
data-bs-placement="bottom"
|
||||||
data-bs-title="Storage used: {{ storage.used_percent }}%"
|
data-bs-title="
|
||||||
|
<span><u>STORAGE</u><span>
|
||||||
|
<br>
|
||||||
|
Used: {{ storage.used_percent }}%
|
||||||
|
<br>
|
||||||
|
Status:
|
||||||
|
<span class={% if storage.status == 'error' %}text-danger{% else %}text-success{% endif %}>
|
||||||
|
{{ storage.status }}
|
||||||
|
<span>
|
||||||
|
"
|
||||||
>
|
>
|
||||||
</i>
|
</i>
|
||||||
<div
|
<div
|
||||||
|
Loading…
Reference in New Issue
Block a user