Compare commits
No commits in common. "7c6114ec3c43e39781d70cc7c1ab81c4a14345a2" and "2e771aa18c4dda8dbd6b76b86da69054a7a45b9b" have entirely different histories.
7c6114ec3c
...
2e771aa18c
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +0,0 @@
|
|||||||
*.swp
|
|
||||||
app/static
|
|
||||||
app/dashboard/migrations/
|
|
||||||
34
Dockerfile
34
Dockerfile
@ -1,34 +0,0 @@
|
|||||||
### DEV ENV ###
|
|
||||||
FROM python:3.9.16-slim-bullseye AS app_dev
|
|
||||||
|
|
||||||
ARG APP_UID=1000
|
|
||||||
ARG APP_GID=1000
|
|
||||||
|
|
||||||
ENV PYTHONDONTWRITEBYTECODE 1
|
|
||||||
ENV PYTHONUNBUFFERED 1
|
|
||||||
|
|
||||||
WORKDIR /app/
|
|
||||||
|
|
||||||
RUN apt update && apt install -y procps less netcat libmariadb-dev-compat libmariadb-dev mariadb-client gcc nginx-light
|
|
||||||
|
|
||||||
COPY ./docker/nginx/updatesdashboard.conf /etc/nginx/sites-enabled/updatesdashboard.conf
|
|
||||||
RUN rm -f /etc/nginx/sites-enabled/default
|
|
||||||
|
|
||||||
COPY ./docker/scripts/entrypoint.dev.sh /usr/local/bin/entrypoint
|
|
||||||
RUN chmod +x /usr/local/bin/entrypoint
|
|
||||||
|
|
||||||
RUN addgroup --system gunicorn --gid ${APP_GID} && adduser --uid ${APP_UID} --system --disabled-login --group gunicorn
|
|
||||||
|
|
||||||
RUN pip install --upgrade pip
|
|
||||||
COPY ./app/requirements.txt .
|
|
||||||
RUN pip install -r requirements.txt
|
|
||||||
|
|
||||||
COPY ./app/ .
|
|
||||||
COPY ./app/updatesdashboard/.env.dev ./updatesdashboard/.env
|
|
||||||
|
|
||||||
RUN python /app/manage.py makemigrations
|
|
||||||
RUN python /app/manage.py makemigrations dashboard
|
|
||||||
|
|
||||||
RUN rm -f ./updatesdashboard/.env
|
|
||||||
|
|
||||||
ENTRYPOINT ["/usr/local/bin/entrypoint","mysql","3306"]
|
|
||||||
@ -10,14 +10,6 @@ It runs with Django. The information are daily generated by an ansible playbook,
|
|||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
### Run with docker
|
|
||||||
|
|
||||||
```
|
|
||||||
docker-compose up
|
|
||||||
```
|
|
||||||
|
|
||||||
### On-premise
|
|
||||||
|
|
||||||
Dependencies in case of Debian 10.
|
Dependencies in case of Debian 10.
|
||||||
```
|
```
|
||||||
apt install python3-venv libmariadb-dev-compat libmariadb-dev mariadb-client python3-dev gcc
|
apt install python3-venv libmariadb-dev-compat libmariadb-dev mariadb-client python3-dev gcc
|
||||||
|
|||||||
@ -1,19 +0,0 @@
|
|||||||
vlearning-db001-tst.infolegale.net;Debian;10;0;5
|
|
||||||
app-db001-tst.infolegale.net;Debian;10;0;9
|
|
||||||
consults-db001-tst.infolegale.net;Debian;10;0;147
|
|
||||||
vador-db001-tst.infolegale.net;Debian;10;0;147
|
|
||||||
tlearning-db003-tst.infolegale.net;Ubuntu;18.04;0;308
|
|
||||||
transdb-db001-tst.infolegale.net;Debian;10;0;147
|
|
||||||
mysql8-db001-tst.infolegale.net;Debian;11;3;119
|
|
||||||
mongo-db001-tst.infolegale.net;Ubuntu;20.04;0;28
|
|
||||||
orchestrator-mgr001-tst.infolegale.net;Ubuntu;20.04;0;28
|
|
||||||
redis5-db001-tst.infolegale.net;Debian;10;0;326
|
|
||||||
redis-db001-tst.infolegale.net;Ubuntu;18.04;0;326
|
|
||||||
docker-hpv001-tst.infolegale.net;Ubuntu;20.04;0;106
|
|
||||||
docker-hpv002-tst.infolegale.net;Ubuntu;20.04;0;398
|
|
||||||
docker-hpv003-tst.infolegale.net;Ubuntu;20.04;0;125
|
|
||||||
rundeck-sch001-tst.infolegale.net;Debian;10;0;91
|
|
||||||
proxysql-db001-tst.infolegale.net;Ubuntu;20.04;0;475
|
|
||||||
docker-hpv005-tst.infolegale.net;Ubuntu;20.04;0;119
|
|
||||||
docker-hpv004-tst.infolegale.net;Ubuntu;20.04;0;28
|
|
||||||
docker-hpv006-tst.infolegale.net;Ubuntu;20.04;0;309
|
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
GUNICORN_CMD_ARGS=--bind=127.0.0.1:3000 --workers=3 --timeout=300 --error-logfile=/var/log/gunicorn-error.log
|
|
||||||
DJANGO_SUPERUSER_PASSWORD=admin
|
|
||||||
SECRET_KEY=uv88xpv8kb2r6j7rubtnhkps
|
|
||||||
DATABASE_NAME=updates_dashboard
|
|
||||||
DATABASE_USER=updates_dashboard
|
|
||||||
DATABASE_PASSWORD=miengetBatheajOf
|
|
||||||
DATABASE_HOST=mysql
|
|
||||||
DATABASE_PORT=3306
|
|
||||||
DJANGO_ALLOWED_HOSTS=localhost 127.0.0.1
|
|
||||||
DJANGO_CSRF_TRUSTED_ORIGINS=http://localhost
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
import environ
|
|
||||||
|
|
||||||
env = environ.Env()
|
|
||||||
# reading .env file
|
|
||||||
environ.Env.read_env()
|
|
||||||
|
|
||||||
ALLOWED_HOSTS = env("DJANGO_ALLOWED_HOSTS").split(" ")
|
|
||||||
CSRF_TRUSTED_ORIGINS = env("DJANGO_CSRF_TRUSTED_ORIGINS").split(" ")
|
|
||||||
SECRET_KEY = env("SECRET_KEY")
|
|
||||||
DATABASES = {
|
|
||||||
'default': {
|
|
||||||
'ENGINE': 'django.db.backends.mysql',
|
|
||||||
'NAME': env("DATABASE_NAME"),
|
|
||||||
'USER': env("DATABASE_USER"),
|
|
||||||
'PASSWORD': env("DATABASE_PASSWORD"),
|
|
||||||
'HOST': env("DATABASE_HOST"),
|
|
||||||
'PORT': int(env("DATABASE_PORT")),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from .models import Os, ServerStatus, Server, PackageStatus
|
from .models import Os, ServerStatus, Server, PackageStatus, Team
|
||||||
|
|
||||||
|
|
||||||
class OsAdmin(admin.ModelAdmin):
|
class OsAdmin(admin.ModelAdmin):
|
||||||
@ -10,3 +10,4 @@ admin.site.register(Os, OsAdmin)
|
|||||||
admin.site.register(ServerStatus)
|
admin.site.register(ServerStatus)
|
||||||
admin.site.register(PackageStatus)
|
admin.site.register(PackageStatus)
|
||||||
admin.site.register(Server)
|
admin.site.register(Server)
|
||||||
|
admin.site.register(Team)
|
||||||
8
dashboard/fixtures/teams.yaml
Normal file
8
dashboard/fixtures/teams.yaml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# This is initial data for prod teams
|
||||||
|
|
||||||
|
- model: dashboard.team
|
||||||
|
pk: null
|
||||||
|
fields: {
|
||||||
|
name: System,
|
||||||
|
color: pink
|
||||||
|
}
|
||||||
@ -32,9 +32,32 @@ class Os(models.Model):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Group(models.Model):
|
||||||
|
name = models.CharField(max_length=50, unique=True)
|
||||||
|
full_name = models.CharField(max_length=50, null=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
if self.full_name:
|
||||||
|
return self.full_name
|
||||||
|
else:
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Team(models.Model):
|
||||||
|
name = models.CharField(max_length=20)
|
||||||
|
color = models.CharField(max_length=20, unique=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Server(models.Model):
|
class Server(models.Model):
|
||||||
hostname = models.CharField(max_length=200, unique=True)
|
hostname = models.CharField(max_length=200, unique=True)
|
||||||
os = models.ForeignKey(Os, null=True, related_name="servers", on_delete=models.SET_NULL)
|
os = models.ForeignKey(Os, null=True, related_name="servers", on_delete=models.SET_NULL)
|
||||||
|
group = models.ForeignKey(Group, null=True, blank=True, related_name="groups", on_delete=models.SET_NULL)
|
||||||
|
team = models.ForeignKey(Team, null=True, related_name="teams", on_delete=models.SET_NULL)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.hostname
|
return self.hostname
|
||||||
|
Before Width: | Height: | Size: 280 KiB After Width: | Height: | Size: 280 KiB |
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 170 KiB After Width: | Height: | Size: 170 KiB |
@ -20,7 +20,7 @@
|
|||||||
<table id="os-list" class="table table-bordered table-hover table-striped">
|
<table id="os-list" class="table table-bordered table-hover table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Distribution</th>
|
<th>Hostname</th>
|
||||||
<th>Number</th>
|
<th>Number</th>
|
||||||
<th>Percentage</th>
|
<th>Percentage</th>
|
||||||
</tr>
|
</tr>
|
||||||
@ -19,6 +19,12 @@ urlpatterns = [
|
|||||||
re_path(r'^server-list/(?P<year>[0-9]{4})/(?P<month>[0-9]{1,2})/(?P<day>[0-9]{1,2})/?$',
|
re_path(r'^server-list/(?P<year>[0-9]{4})/(?P<month>[0-9]{1,2})/(?P<day>[0-9]{1,2})/?$',
|
||||||
views.server_list,
|
views.server_list,
|
||||||
name='server-list-by-date'),
|
name='server-list-by-date'),
|
||||||
|
re_path(r'^server-list/(?P<group>[a-z0-9\-_]*)/(?P<year>[0-9]{4})/(?P<month>[0-9]{1,2})/(?P<day>[0-9]{1,2})/?$',
|
||||||
|
views.server_list,
|
||||||
|
name='server-list-by-group'),
|
||||||
|
re_path(r'^server-list/team/(?P<team>[a-z]*)/(?P<year>[0-9]{4})/(?P<month>[0-9]{1,2})/(?P<day>[0-9]{1,2})/?$',
|
||||||
|
views.server_list,
|
||||||
|
name='server-list-by-team'),
|
||||||
|
|
||||||
# package list
|
# package list
|
||||||
re_path(r'^packages/?$',
|
re_path(r'^packages/?$',
|
||||||
@ -63,6 +69,9 @@ urlpatterns = [
|
|||||||
re_path(r'^manage-packages/upload_csv_results_packages',
|
re_path(r'^manage-packages/upload_csv_results_packages',
|
||||||
views.upload_csv_results_packages,
|
views.upload_csv_results_packages,
|
||||||
name='upload_csv_results_packages'),
|
name='upload_csv_results_packages'),
|
||||||
|
# re_path(r'^manage/update-groups/?$',
|
||||||
|
# views.update_groups,
|
||||||
|
# name='update_groups'),
|
||||||
|
|
||||||
# manage packages
|
# manage packages
|
||||||
re_path(r'^manage-packages/?$',
|
re_path(r'^manage-packages/?$',
|
||||||
@ -16,7 +16,7 @@ from django.core.cache import cache
|
|||||||
from django.db import IntegrityError
|
from django.db import IntegrityError
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
# project
|
# project
|
||||||
from .models import Os, Server, ServerStatus, PackageStatus, Document_Servers, Document_Packages
|
from .models import Os, Group, Server, ServerStatus, PackageStatus, Team, Document_Servers, Document_Packages
|
||||||
from .forms import DocumentForm
|
from .forms import DocumentForm
|
||||||
|
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ def index(request):
|
|||||||
## -----------------------------------------------------------------------------
|
## -----------------------------------------------------------------------------
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def server_list(request, year=None, month=None, day=None):
|
def server_list(request, year=None, month=None, day=None, group=None, team=None):
|
||||||
# TODO: use date.today?
|
# TODO: use date.today?
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
if not year or not month or not day:
|
if not year or not month or not day:
|
||||||
@ -64,10 +64,23 @@ def server_list(request, year=None, month=None, day=None):
|
|||||||
next_result_date = next_result.date
|
next_result_date = next_result.date
|
||||||
|
|
||||||
results_date = current_date
|
results_date = current_date
|
||||||
# status_list = ServerStatus.objects.filter(date=current_date).order_by('server__hostname')
|
if group:
|
||||||
status_list = ServerStatus.objects.filter(date=current_date).order_by('server__hostname').select_related('server', 'server__os')
|
group = get_object_or_404(Group, name=group)
|
||||||
|
status_list = ServerStatus.objects.filter(date=current_date, server__group=group).order_by('server__hostname')
|
||||||
if previous_result and not status_list:
|
if previous_result and not status_list:
|
||||||
status_list = ServerStatus.objects.filter(date=previous_result_date).order_by('server__hostname').select_related('server', 'server__os')
|
status_list = ServerStatus.objects.filter(date=previous_result_date, server__group=group).order_by('server__hostname')
|
||||||
|
results_date = previous_result_date
|
||||||
|
elif team:
|
||||||
|
team = get_object_or_404(Team, color=team)
|
||||||
|
status_list = ServerStatus.objects.filter(date=current_date, server__team=team).order_by('server__hostname')
|
||||||
|
if previous_result and not status_list:
|
||||||
|
status_list = ServerStatus.objects.filter(date=previous_result_date, server__team=team).order_by('server__hostname')
|
||||||
|
results_date = previous_result_date
|
||||||
|
else:
|
||||||
|
# status_list = ServerStatus.objects.filter(date=current_date).order_by('server__hostname')
|
||||||
|
status_list = ServerStatus.objects.filter(date=current_date).order_by('server__hostname').select_related('server', 'server__group', 'server__os')
|
||||||
|
if previous_result and not status_list:
|
||||||
|
status_list = ServerStatus.objects.filter(date=previous_result_date).order_by('server__hostname').select_related('server', 'server__group', 'server__os')
|
||||||
results_date = previous_result_date
|
results_date = previous_result_date
|
||||||
|
|
||||||
if not status_list:
|
if not status_list:
|
||||||
@ -77,6 +90,7 @@ def server_list(request, year=None, month=None, day=None):
|
|||||||
|
|
||||||
return render(request, 'server-list.html',
|
return render(request, 'server-list.html',
|
||||||
{
|
{
|
||||||
|
'group': group,
|
||||||
'status_list': status_list,
|
'status_list': status_list,
|
||||||
'results_date': results_date,
|
'results_date': results_date,
|
||||||
'previous_result_date': previous_result_date,
|
'previous_result_date': previous_result_date,
|
||||||
@ -318,6 +332,7 @@ def purge_all(request):
|
|||||||
ServerStatus.objects.all().delete()
|
ServerStatus.objects.all().delete()
|
||||||
Os.objects.all().delete()
|
Os.objects.all().delete()
|
||||||
PackageStatus.objects.all().delete()
|
PackageStatus.objects.all().delete()
|
||||||
|
Group.objects.all().delete()
|
||||||
|
|
||||||
content = "<div class='alert alert-danger' role='alert'>Everything has been purged.</div>"
|
content = "<div class='alert alert-danger' role='alert'>Everything has been purged.</div>"
|
||||||
|
|
||||||
@ -37,9 +37,37 @@ INSTALLED_APPS_LOCAL = [
|
|||||||
|
|
||||||
# LDAP AUTH
|
# LDAP AUTH
|
||||||
AUTHENTICATION_BACKENDS = (
|
AUTHENTICATION_BACKENDS = (
|
||||||
|
'django_python3_ldap.auth.LDAPBackend',
|
||||||
'django.contrib.auth.backends.ModelBackend',
|
'django.contrib.auth.backends.ModelBackend',
|
||||||
)
|
)
|
||||||
|
LDAP_AUTH_URL = "ldaps://SERVER:PORT"
|
||||||
|
LDAP_AUTH_USE_TLS = True
|
||||||
|
LDAP_AUTH_SEARCH_BASE = "ou=USERS,dc=MY,dc=ORG"
|
||||||
|
LDAP_AUTH_OBJECT_CLASS = "inetOrgPerson"
|
||||||
|
LDAP_AUTH_USER_FIELDS = {
|
||||||
|
"username": "uid",
|
||||||
|
"first_name": "givenName",
|
||||||
|
"last_name": "sn",
|
||||||
|
"email": "mail",
|
||||||
|
}
|
||||||
|
LDAP_AUTH_FORMAT_SEARCH_FILTERS = "dashboard.module.custom_format_search_filters"
|
||||||
|
LDAP_AUTH_CUSTOM_OBJECT_CLASS = "ACLASS"
|
||||||
|
LDAP_AUTH_CUSTOM_FILTERS = "(SOMEFIELD=SOMEVALUE)"
|
||||||
|
|
||||||
MIDDLEWARE_LOCAL = [
|
MIDDLEWARE_LOCAL = [
|
||||||
'debug_toolbar.middleware.DebugToolbarMiddleware',
|
'debug_toolbar.middleware.DebugToolbarMiddleware',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Static files (CSS, JavaScript, Images)
|
||||||
|
# https://docs.djangoproject.com/en/1.10/howto/static-files/
|
||||||
|
|
||||||
|
STATIC_URL = '/static/'
|
||||||
|
STATIC_ROOT = os.path.join(BASE_DIR, './static')
|
||||||
|
|
||||||
|
# custom
|
||||||
|
RESULT_DIR = os.path.join(BASE_DIR, 'results')
|
||||||
|
RESULT_PACKAGES_DIR = os.path.join(BASE_DIR, 'results-packages')
|
||||||
|
INVENTORY_DIR = os.path.join(BASE_DIR, 'inventory')
|
||||||
|
|
||||||
|
LOGIN_URL = '/login'
|
||||||
|
LOGIN_REDIRECT_URL = 'index'
|
||||||
@ -1,33 +0,0 @@
|
|||||||
version: '0.1'
|
|
||||||
services:
|
|
||||||
web:
|
|
||||||
container_name: updatesdashboard.front
|
|
||||||
build:
|
|
||||||
context: ./
|
|
||||||
target: app_dev
|
|
||||||
ports:
|
|
||||||
- "3000:3001"
|
|
||||||
volumes:
|
|
||||||
- ./app/:/app/
|
|
||||||
env_file:
|
|
||||||
- ./app/updatesdashboard/.env.dev
|
|
||||||
networks:
|
|
||||||
- updates-dashboard-network
|
|
||||||
depends_on:
|
|
||||||
- mysql
|
|
||||||
mysql:
|
|
||||||
image: mysql:8.0
|
|
||||||
container_name: updatesdashboard.mysql
|
|
||||||
environment:
|
|
||||||
MYSQL_ROOT_PASSWORD: root
|
|
||||||
MYSQL_DATABASE: updates_dashboard
|
|
||||||
MYSQL_USER: updates_dashboard
|
|
||||||
MYSQL_PASSWORD: miengetBatheajOf
|
|
||||||
ports:
|
|
||||||
- "3306:3306"
|
|
||||||
networks:
|
|
||||||
- updates-dashboard-network
|
|
||||||
networks:
|
|
||||||
updates-dashboard-network:
|
|
||||||
driver: bridge
|
|
||||||
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
server {
|
|
||||||
listen 3001;
|
|
||||||
server_name updates-dashboard.infolegale.net;
|
|
||||||
|
|
||||||
# css, js…
|
|
||||||
location /static {
|
|
||||||
alias /app/static;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($request_uri !~ "^/admin.*") {
|
|
||||||
# don't rewrite admin
|
|
||||||
rewrite ^/(.*)/$ /$1 permanent;
|
|
||||||
}
|
|
||||||
|
|
||||||
location / {
|
|
||||||
include proxy_params;
|
|
||||||
proxy_pass http://127.0.0.1:3000;
|
|
||||||
proxy_connect_timeout 120s;
|
|
||||||
proxy_read_timeout 300s;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
error_log /var/log/updatesdashboard-error.log;
|
|
||||||
access_log /var/log/updatesdashboard-access.log;
|
|
||||||
}
|
|
||||||
@ -1,11 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
until nc -vz $1 $2; do echo "Waiting for MySQL $1:$2..."; sleep 3; done;
|
|
||||||
|
|
||||||
python /app/manage.py migrate
|
|
||||||
python /app/manage.py collectstatic
|
|
||||||
python /app/manage.py loaddata /app/dashboard/fixtures/os.yaml
|
|
||||||
python /app/manage.py createsuperuser --noinput --username admin --email test@example.com
|
|
||||||
service nginx start
|
|
||||||
gunicorn updatesdashboard.wsgi:application
|
|
||||||
|
|
||||||
exec "$@"
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
until nc -vz $1 $2; do echo "Waiting for MySQL $1:$2..."; sleep 3; done;
|
|
||||||
|
|
||||||
#python /app/manage.py flush --no-input
|
|
||||||
#python /app/manage.py migrate
|
|
||||||
#python /app/manage.py loaddata dashboard/fixtures/os.yaml
|
|
||||||
|
|
||||||
exec "$@"
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user