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
|
||||
ARG VERSION=0.1.0 \
|
||||
APP_DIR=/app \
|
||||
DATA_DIR=/app/data \
|
||||
SRC_DIR=./logs_collector \
|
||||
SCRIPTS_DIR=./scripts \
|
||||
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/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 && \
|
||||
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
|
||||
USER ${USER_NAME}
|
||||
|
||||
# copy src and entrypoint.sh to 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
|
||||
WORKDIR ${APP_DIR}
|
||||
|
@ -13,6 +13,7 @@ services:
|
||||
- SRC_DIR=${SRC_DIR}
|
||||
- SCRIPTS_DIR=${SCRIPTS_DIR}
|
||||
- APP_DIR=${APP_DIR}
|
||||
- DATA_DIR=${DATA_DIR}
|
||||
- WEB_PORT=${WEB_PORT}
|
||||
- USER_NAME=${USER_NAME}
|
||||
- USER_GROUP=${USER_GROUP}
|
||||
|
@ -66,3 +66,4 @@ class StorageInfoSerializer(serializers.Serializer):
|
||||
used = serializers.IntegerField(read_only=True)
|
||||
free = 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'
|
||||
)
|
||||
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):
|
||||
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 pathlib
|
||||
|
||||
|
||||
def logs_dir_path(instance, filename):
|
||||
def logs_dir_path(instance, filename: str) -> str:
|
||||
"""
|
||||
file will be uploaded to
|
||||
MEDIA_ROOT/view/<filename>
|
||||
@ -30,9 +31,31 @@ def sizify(value: int) -> str:
|
||||
return f'{round(value, 1)} {ext}'
|
||||
|
||||
|
||||
def get_mount_fs_info(path):
|
||||
mount_info = shutil.disk_usage(path)._asdict()
|
||||
mount_info['used_percent'] = round(
|
||||
mount_info['used'] / mount_info['total'] * 100
|
||||
)
|
||||
def get_mount_fs_info(path: type[pathlib.PosixPath]) -> dict:
|
||||
"""
|
||||
Get directory information for storing uploaded files.
|
||||
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
|
||||
|
@ -4,9 +4,19 @@ from datetime import timedelta
|
||||
|
||||
from . import __version__, __status__
|
||||
|
||||
|
||||
# █▀█ █▀█ █▀█ ▀█▀ ▀
|
||||
# █▀▄ █▄█ █▄█ ░█░ ▄
|
||||
# -- -- -- -- -- --
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
# █▀▀ █▄░█ █░█ ▀
|
||||
# ██▄ █░▀█ ▀▄▀ ▄
|
||||
# -- -- -- -- --
|
||||
|
||||
# Set default environ variables:
|
||||
env = environ.Env(
|
||||
# set casting default value
|
||||
@ -14,7 +24,7 @@ env = environ.Env(
|
||||
ENVIRONMENT=(str, __status__),
|
||||
DEBUG=(bool, False),
|
||||
SECRET_KEY=(str, 'j9QGbvM9Z4otb47'),
|
||||
SQLITE_URL=(str, f'sqlite:///{BASE_DIR / "data/db.sqlite3"}'),
|
||||
DATA_DIR=(str, BASE_DIR / 'data'),
|
||||
CSRF_TRUSTED_ORIGINS=(list, []),
|
||||
ALLOWED_HOSTS=(list, ['*']),
|
||||
TZ=(str, 'UTC'),
|
||||
@ -23,7 +33,13 @@ env = environ.Env(
|
||||
# Read .env file if exist:
|
||||
environ.Env.read_env(BASE_DIR / '.env')
|
||||
|
||||
|
||||
# █▀▀ █▀█ █▀█ █▀▀ ▀
|
||||
# █▄▄ █▄█ █▀▄ ██▄ ▄
|
||||
# -- -- -- -- -- -
|
||||
|
||||
VERSION = env('VERSION')
|
||||
|
||||
ENVIRONMENT = env('ENVIRONMENT')
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
@ -99,12 +115,6 @@ TEMPLATES = [
|
||||
|
||||
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
|
||||
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
|
||||
|
||||
@ -134,6 +144,11 @@ USE_I18N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# █▀ ▀█▀ ▄▀█ ▀█▀ █ █▀▀ ▀
|
||||
# ▄█ ░█░ █▀█ ░█░ █ █▄▄ ▄
|
||||
# -- -- -- -- -- -- -- -
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/4.2/howto/static-files/
|
||||
# Whitenoise:
|
||||
@ -141,12 +156,19 @@ USE_TZ = True
|
||||
STATIC_URL = '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 = {
|
||||
"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
|
||||
# https://django-crispy-forms.readthedocs.io/en/latest/
|
||||
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
|
||||
@ -196,7 +241,6 @@ if DEBUG:
|
||||
).append('rest_framework.renderers.BrowsableAPIRenderer')
|
||||
|
||||
# https://drf-spectacular.readthedocs.io/en/latest/readme.html
|
||||
# TODO: set environ vars config!
|
||||
SPECTACULAR_SETTINGS = {
|
||||
'TITLE': 'Logs collector API',
|
||||
'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
|
||||
}
|
||||
|
||||
|
||||
# ▄▀█ █░█ ▀█▀ █░█ ▀
|
||||
# █▀█ █▄█ ░█░ █▀█ ▄
|
||||
# -- -- -- -- -- --
|
||||
|
||||
LOGIN_URL = 'two_factor:login'
|
||||
LOGIN_REDIRECT_URL = 'collector:index'
|
||||
LOGOUT_REDIRECT_URL = 'two_factor:login'
|
||||
|
@ -5,8 +5,18 @@
|
||||
class="nav-link me-1 bi bi-sd-card"
|
||||
aria-current="page"
|
||||
data-bs-toggle="tooltip"
|
||||
data-bs-html="true"
|
||||
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>
|
||||
<div
|
||||
|
Loading…
Reference in New Issue
Block a user