Compare commits

...

10 Commits

Author SHA1 Message Date
Holger Sielaff
2e9692777f debugging 2025-09-25 09:17:00 +02:00
Holger Sielaff
da05164bcc debugging 2025-09-25 09:10:57 +02:00
Holger Sielaff
bba570f87d debuging 2025-09-25 08:52:18 +02:00
Holger Sielaff
d1abb0d1f5 user_profile may be emtpy on post 2025-09-25 08:51:14 +02:00
Holger Sielaff
8097893eee csrf_exempt for create_container 2025-09-25 08:48:52 +02:00
Holger Sielaff
d10938d2d2 statuf on load fixed? 2025-09-04 10:15:41 +02:00
Holger Sielaff
c5e7e3739f fix cookie stuff? 2025-09-04 09:52:23 +02:00
Holger Sielaff
26fce651b1 ircular import (i hate ai) 2025-09-04 09:33:31 +02:00
Holger Sielaff
26cc248cab stop/restart on clone running container 2025-09-04 09:31:54 +02:00
Holger Sielaff
25b77977ff wrong params in clone machine 2025-09-04 08:55:40 +02:00
7 changed files with 65 additions and 20 deletions
+2
View File
@@ -42,6 +42,8 @@ DEBUG = True
ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '127.0.0.1,localhost').strip().replace(' ', '').split(',') ALLOWED_HOSTS = os.environ.get('ALLOWED_HOSTS', '127.0.0.1,localhost').strip().replace(' ', '').split(',')
ADMIN_BASE_URL = os.environ.get('ADMIN_BASE_URL', '/admin/')
INSTALLED_APPS = [ INSTALLED_APPS = [
'django.contrib.auth', 'django.contrib.auth',
'django.contrib.contenttypes', 'django.contrib.contenttypes',
+4 -2
View File
@@ -1,4 +1,5 @@
from django.contrib import admin from django.contrib import admin
""" """
URL configuration for django_proxmox_mikrotik project. URL configuration for django_proxmox_mikrotik project.
@@ -17,9 +18,10 @@ Including another URLconf
""" """
from django.urls import path, include from django.urls import path, include
from django.shortcuts import redirect from django.shortcuts import redirect
from .settings import ADMIN_BASE_URL
urlpatterns = [ urlpatterns = [
path('admin/', admin.site.urls), path(ADMIN_BASE_URL.strip('/') + '/', admin.site.urls),
] ]
# django_proxmox_mikrotik/urls.py # django_proxmox_mikrotik/urls.py
@@ -28,4 +30,4 @@ urlpatterns += [
path('frontend/', include('frontend.urls', namespace='frontend')), path('frontend/', include('frontend.urls', namespace='frontend')),
path('manager/', include('manager.urls', namespace='manager')), path('manager/', include('manager.urls', namespace='manager')),
path('tasklogger/', include('tasklogger.urls', namespace='tasklogger')), path('tasklogger/', include('tasklogger.urls', namespace='tasklogger')),
] ]
+4 -1
View File
@@ -1,12 +1,15 @@
from django.conf import settings from django.conf import settings
from django_proxmox_mikrotik.settings import ADMIN_BASE_URL
class FrontendSessionMiddleware: class FrontendSessionMiddleware:
def __init__(self, get_response): def __init__(self, get_response):
self.get_response = get_response self.get_response = get_response
self.default_session_cookie_name = 'sessionid' self.default_session_cookie_name = 'sessionid'
def __call__(self, request): def __call__(self, request):
if request.path.startswith('/frontend/'): if not request.path.startswith(ADMIN_BASE_URL):
settings.SESSION_COOKIE_NAME = settings.SESSION_COOKIE_NAME_FRONTEND settings.SESSION_COOKIE_NAME = settings.SESSION_COOKIE_NAME_FRONTEND
else: else:
settings.SESSION_COOKIE_NAME = self.default_session_cookie_name settings.SESSION_COOKIE_NAME = self.default_session_cookie_name
+3 -6
View File
@@ -282,12 +282,9 @@
$.get("{% url 'frontend:current_container_details' %}", {'ids': id}, function (container) { $.get("{% url 'frontend:current_container_details' %}", {'ids': id}, function (container) {
container = container[0] container = container[0]
if (container.is_low) { if (container.is_low) {
$('[data-crow="' + id + '"]').addClass( $('[data-crow="' + id + '"]')
'status-low' .addClass('status-low')
).attr( .attr('title', 'Low Warning: Disk: ' + container.disk_percent + '%, Memory: ' + container.mem_percent + '%');
'title',
'Low Warning: Disk: ' + container.disk_percent + '%, Memory: ' + container.mem_percent + '%'
);
} }
let lxc_status = $('.lxc_status_' + id); let lxc_status = $('.lxc_status_' + id);
let lease_status = $('.lease_status_' + id); let lease_status = $('.lease_status_' + id);
+15 -5
View File
@@ -1,4 +1,5 @@
import json import json
import logging
import threading import threading
from django.contrib import messages from django.contrib import messages
@@ -8,6 +9,7 @@ from django.db.models import Q
from django.forms import model_to_dict from django.forms import model_to_dict
from django.http import HttpResponse, HttpResponseForbidden from django.http import HttpResponse, HttpResponseForbidden
from django.shortcuts import get_object_or_404, redirect, render from django.shortcuts import get_object_or_404, redirect, render
from django.views.decorators.csrf import csrf_exempt
from django_proxmox_mikrotik.settings import ProxmoxConfig from django_proxmox_mikrotik.settings import ProxmoxConfig
from lib.decorators import readonly from lib.decorators import readonly
@@ -107,7 +109,11 @@ def dashboard(request):
class ContainerStatus: class ContainerStatus:
low_limit = 80 low_limit = 80
def __init__(self, **kwargs): def __init__(self, dev_container:DevContainer):
self._devcontainer = dev_container
self.vmid = dev_container.lxc.vmid
self.lxc_status = dev_container.lxc.synced_status
kwargs = dev_container.statuscache or {}
self.cpus = kwargs.get('cpus', 0) self.cpus = kwargs.get('cpus', 0)
self.cpu = kwargs.get('cpu', 0) self.cpu = kwargs.get('cpu', 0)
self.maxmem = kwargs.get('maxmem', 256) self.maxmem = kwargs.get('maxmem', 256)
@@ -117,9 +123,7 @@ class ContainerStatus:
self.maxswap = kwargs.get('maxswap', 0) self.maxswap = kwargs.get('maxswap', 0)
self.swap = kwargs.get('swap', 0) self.swap = kwargs.get('swap', 0)
self.status = kwargs.get('status') self.status = kwargs.get('status')
self.vmid = kwargs.get('vmid')
self.lease_status = kwargs.get('lease_status', 'waiting') self.lease_status = kwargs.get('lease_status', 'waiting')
self.lxc_status = kwargs.get('lxc_status', 'stopped')
def __hash__(self): def __hash__(self):
return int(self.vmid) return int(self.vmid)
@@ -171,7 +175,7 @@ def container_details(request):
with Proxmox() as pm: with Proxmox() as pm:
for id in ids: for id in ids:
container = DevContainer.objects.get(internal_id=id) container = DevContainer.objects.get(internal_id=id)
ret.append(ContainerStatus(**(container.statuscache or {})).to_json) ret.append(ContainerStatus(container).to_json)
return HttpResponse(json.dumps(ret), content_type='application/json') return HttpResponse(json.dumps(ret), content_type='application/json')
@@ -353,10 +357,16 @@ def delete_container(request, container_id):
}) })
@csrf_exempt
def create_container(request): def create_container(request):
user_profile = request.user.profile try:
user_profile = request.user.profile
except AttributeError as e:
logging.error(f"{e}")
user_profile = None
if request.method == 'POST': if request.method == 'POST':
logging.info(f"POST is {request.POST}")
# Get task_uuid from form # Get task_uuid from form
task_uuid = request.POST.get('task_uuid') task_uuid = request.POST.get('task_uuid')
+18 -2
View File
@@ -87,6 +87,11 @@ class CloneContainer(CloneAbstract):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self._old_active = self.is_active self._old_active = self.is_active
def get_clone_machine_status(self):
self.vm.sync_from_proxmox()
return self.vm.status
def execute(self, task_uuid_override=None, *args, **kwargs): def execute(self, task_uuid_override=None, *args, **kwargs):
from proxmox.models import Lxc from proxmox.models import Lxc
from tasklogger.models import TaskFactory from tasklogger.models import TaskFactory
@@ -99,6 +104,12 @@ class CloneContainer(CloneAbstract):
try: try:
data = self.proxmox_data data = self.proxmox_data
old_status = None
if self.vm:
old_status = self.get_clone_machine_status()
if old_status == 'running':
task.add_entry(f"Stopping container '{self.vm.name}'")
self.vm.stop()
pm = Proxmox() pm = Proxmox()
route = data.pop('route') route = data.pop('route')
vmdata = data.pop('vm') vmdata = data.pop('vm')
@@ -110,12 +121,12 @@ class CloneContainer(CloneAbstract):
vmparams = { vmparams = {
'hostname': vmdata['hostname'], 'hostname': vmdata['hostname'],
'description': vmdata['description'], 'description': vmdata['description'],
'cores': vmdata['cores'],
'memory': vmdata['memory'],
} }
if vmdata['template']: if vmdata['template']:
vmparams |= { vmparams |= {
'vmid': vmdata['newid'], 'vmid': vmdata['newid'],
'cores': vmdata['cores'],
'memory': vmdata['memory'],
'ostemplate': self.template.volid, 'ostemplate': self.template.volid,
'net0': vmdata['net0'], 'net0': vmdata['net0'],
'features': 'nesting=1', 'features': 'nesting=1',
@@ -128,6 +139,7 @@ class CloneContainer(CloneAbstract):
} }
task.add_entry(f"Cloning container {self.vm.vmid}") task.add_entry(f"Cloning container {self.vm.vmid}")
success = False success = False
lxc = None lxc = None
lease = None lease = None
@@ -141,9 +153,13 @@ class CloneContainer(CloneAbstract):
def _lxc_post(): def _lxc_post():
return pm.lxc_post(route, **vmparams) return pm.lxc_post(route, **vmparams)
def _restart_cloned():
return self.vm.start()
# Wrap the proxmox function - this handles UPID monitoring synchronously # Wrap the proxmox function - this handles UPID monitoring synchronously
task.wrap_proxmox_function(_lxc_post) task.wrap_proxmox_function(_lxc_post)
if old_status == 'running':
task.wrap_proxmox_function(_restart_cloned)
task.add_entry("Container creation completed") task.add_entry("Container creation completed")
success = True success = True
+19 -4
View File
@@ -58,9 +58,10 @@ class ProxmoxAbstractModel(BaseModel, TaskAwareModelMixin):
def int_fields(self): def int_fields(self):
return [] return []
def from_proxmox(self, **kwargs): def from_proxmox(self, write_to_db=True, **kwargs):
"""Sets the values in DB """Sets the values in DB
Extracts csv Values into self, if given""" Extracts csv Values into self, if given"""
logging.debug(f"Got {kwargs} from proxmox") logging.debug(f"Got {kwargs} from proxmox")
kwkeys = list(kwargs.keys()) kwkeys = list(kwargs.keys())
params = {} params = {}
@@ -92,7 +93,13 @@ class ProxmoxAbstractModel(BaseModel, TaskAwareModelMixin):
v = no_int_re.sub('', _v) or 0 v = no_int_re.sub('', _v) or 0
params[k] = v params[k] = v
logging.debug(f"No CSValues for {self}") logging.debug(f"No CSValues for {self}")
return self.write(**params) if write_to_db:
return self.write(**params)
else:
return params
@property
def vmstatus(self):
raise NotImplemented('vmstatus not implemented')
class Lxc(ProxmoxAbstractModel): class Lxc(ProxmoxAbstractModel):
@@ -119,6 +126,13 @@ class Lxc(ProxmoxAbstractModel):
'rootfs': ('size', 'disksize', lambda x: int(no_int_re.sub('', x) or 0)), 'rootfs': ('size', 'disksize', lambda x: int(no_int_re.sub('', x) or 0)),
} }
@property
def synced_status(self):
with Proxmox() as pm:
if statusresponse := pm.lxc_get(f'{self.vmid}/status/current'):
self.write(status=statusresponse['status'])
return self.status
@property @property
def proxmox_console_url(self): def proxmox_console_url(self):
return ( return (
@@ -205,8 +219,9 @@ class Lxc(ProxmoxAbstractModel):
if not data: if not data:
logging.warning(f'Could not find {self.vmid} in proxmox - deleting from local database!') logging.warning(f'Could not find {self.vmid} in proxmox - deleting from local database!')
return self.delete() return self.delete()
self.from_proxmox(**data) statusdata = pm.lxc_get(f'{self.vmid}/status/current')
super().save() data |= statusdata
self.from_proxmox(write_to_db=True, **data)
except Exception as e: except Exception as e:
logging.error(f"Could not get config for {self.vmid} - {e}") logging.error(f"Could not get config for {self.vmid} - {e}")
return self return self