mirror of
https://github.com/retspen/webvirtcloud
synced 2025-07-31 12:41:08 +00:00
Added admin application
- Manage users - Manage groups - Manage logs
This commit is contained in:
parent
713d565a2d
commit
fec59b1dd7
37 changed files with 1106 additions and 517 deletions
|
|
@ -5,6 +5,6 @@ from . import views
|
|||
urlpatterns = [
|
||||
path('login/', auth_views.LoginView.as_view(template_name='login.html'), name='login'),
|
||||
path('logout/', auth_views.LogoutView.as_view(template_name='logout.html'), name='logout'),
|
||||
path('profile/', views.profile, name='profile'), path('', views.accounts, name='accounts'),
|
||||
path('profile/', views.profile, name='profile'),
|
||||
path('profile/<int:user_id>/', views.account, name='account'),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
|
||||
from django.shortcuts import render
|
||||
from django.core.validators import ValidationError
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import render
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.core.validators import ValidationError
|
||||
from instances.models import Instance
|
||||
from accounts.models import *
|
||||
from appsettings.models import AppSettings
|
||||
|
||||
from accounts.forms import UserAddForm
|
||||
from accounts.models import *
|
||||
from admin.decorators import superuser_only
|
||||
from appsettings.models import AppSettings
|
||||
from instances.models import Instance
|
||||
|
||||
import sass
|
||||
import os
|
||||
|
|
@ -19,7 +20,7 @@ def profile(request):
|
|||
"""
|
||||
|
||||
error_messages = []
|
||||
user = User.objects.get(id=request.user.id)
|
||||
# user = User.objects.get(id=request.user.id)
|
||||
publickeys = UserSSHKey.objects.filter(user_id=request.user.id)
|
||||
show_profile_edit_password = AppSettings.objects.get(key="SHOW_PROFILE_EDIT_PASSWORD").value
|
||||
|
||||
|
|
@ -29,7 +30,7 @@ def profile(request):
|
|||
email = request.POST.get('email', '')
|
||||
user.first_name = username
|
||||
user.email = email
|
||||
user.save()
|
||||
request.user.save()
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
if 'oldpasswd' in request.POST:
|
||||
oldpasswd = request.POST.get('oldpasswd', '')
|
||||
|
|
@ -39,11 +40,11 @@ def profile(request):
|
|||
error_messages.append("Passwords didn't enter")
|
||||
if password1 and password2 and password1 != password2:
|
||||
error_messages.append("Passwords don't match")
|
||||
if not user.check_password(oldpasswd):
|
||||
if not request.user.check_password(oldpasswd):
|
||||
error_messages.append("Old password is wrong!")
|
||||
if not error_messages:
|
||||
user.set_password(password1)
|
||||
user.save()
|
||||
request.user.set_password(password1)
|
||||
request.user.save()
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
if 'keyname' in request.POST:
|
||||
keyname = request.POST.get('keyname', '')
|
||||
|
|
@ -69,87 +70,7 @@ def profile(request):
|
|||
return HttpResponseRedirect(request.get_full_path())
|
||||
return render(request, 'profile.html', locals())
|
||||
|
||||
|
||||
def accounts(request):
|
||||
"""
|
||||
:param request:
|
||||
:return:
|
||||
"""
|
||||
if not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
error_messages = []
|
||||
users = User.objects.all().order_by('username')
|
||||
appsettings = AppSettings.objects.all()
|
||||
allow_empty_password = appsettings.get(key="ALLOW_EMPTY_PASSWORD").value
|
||||
|
||||
if request.method == 'POST':
|
||||
if 'create' in request.POST:
|
||||
form = UserAddForm(request.POST)
|
||||
if form.is_valid():
|
||||
data = form.cleaned_data
|
||||
else:
|
||||
for msg_err in form.errors.values():
|
||||
error_messages.append(msg_err.as_text())
|
||||
if not error_messages:
|
||||
new_user = User.objects.create_user(data['name'], None, data['password'])
|
||||
new_user.save()
|
||||
UserAttributes.configure_user(new_user)
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
if 'edit' in request.POST:
|
||||
CHECKBOX_MAPPING = {'on': True, 'off': False, }
|
||||
|
||||
user_id = request.POST.get('user_id', '')
|
||||
user_pass = request.POST.get('user_pass', '')
|
||||
user_edit = User.objects.get(id=user_id)
|
||||
|
||||
if user_pass != '': user_edit.set_password(user_pass)
|
||||
user_edit.is_staff = CHECKBOX_MAPPING.get(request.POST.get('user_is_staff', 'off'))
|
||||
user_edit.is_superuser = CHECKBOX_MAPPING.get(request.POST.get('user_is_superuser', 'off'))
|
||||
user_edit.save()
|
||||
|
||||
UserAttributes.create_missing_userattributes(user_edit)
|
||||
user_edit.userattributes.can_clone_instances = CHECKBOX_MAPPING.get(request.POST.get('userattributes_can_clone_instances', 'off'))
|
||||
user_edit.userattributes.max_instances = request.POST.get('userattributes_max_instances', 0)
|
||||
user_edit.userattributes.max_cpus = request.POST.get('userattributes_max_cpus', 0)
|
||||
user_edit.userattributes.max_memory = request.POST.get('userattributes_max_memory', 0)
|
||||
user_edit.userattributes.max_disk_size = request.POST.get('userattributes_max_disk_size', 0)
|
||||
|
||||
try:
|
||||
user_edit.userattributes.clean_fields()
|
||||
except ValidationError as exc:
|
||||
error_messages.append(exc)
|
||||
else:
|
||||
user_edit.userattributes.save()
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
if 'block' in request.POST:
|
||||
user_id = request.POST.get('user_id', '')
|
||||
user_block = User.objects.get(id=user_id)
|
||||
user_block.is_active = False
|
||||
user_block.save()
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
if 'unblock' in request.POST:
|
||||
user_id = request.POST.get('user_id', '')
|
||||
user_unblock = User.objects.get(id=user_id)
|
||||
user_unblock.is_active = True
|
||||
user_unblock.save()
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
if 'delete' in request.POST:
|
||||
user_id = request.POST.get('user_id', '')
|
||||
try:
|
||||
del_user_inst = UserInstance.objects.filter(user_id=user_id)
|
||||
del_user_inst.delete()
|
||||
finally:
|
||||
user_delete = User.objects.get(id=user_id)
|
||||
user_delete.delete()
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
|
||||
accounts_template_file = 'accounts.html'
|
||||
if appsettings.get(key="VIEW_ACCOUNTS_STYLE").value == "list":
|
||||
accounts_template_file = 'accounts-list.html'
|
||||
return render(request, accounts_template_file, locals())
|
||||
|
||||
|
||||
@superuser_only
|
||||
def account(request, user_id):
|
||||
"""
|
||||
:param request:
|
||||
|
|
@ -157,9 +78,6 @@ def account(request, user_id):
|
|||
:return:
|
||||
"""
|
||||
|
||||
if not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
error_messages = []
|
||||
user = User.objects.get(id=user_id)
|
||||
user_insts = UserInstance.objects.filter(user_id=user_id)
|
||||
|
|
@ -190,7 +108,7 @@ def account(request, user_id):
|
|||
check_inst = UserInstance.objects.filter(instance_id=int(inst_id), user_id=int(user_id))
|
||||
else:
|
||||
check_inst = UserInstance.objects.filter(instance_id=int(inst_id))
|
||||
|
||||
|
||||
if check_inst:
|
||||
msg = _("Instance already added")
|
||||
error_messages.append(msg)
|
||||
|
|
|
|||
5
admin/apps.py
Normal file
5
admin/apps.py
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class AdminConfig(AppConfig):
|
||||
name = 'admin'
|
||||
10
admin/decorators.py
Normal file
10
admin/decorators.py
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
from django.core.exceptions import PermissionDenied
|
||||
|
||||
|
||||
def superuser_only(function):
|
||||
def _inner(request, *args, **kwargs):
|
||||
if not request.user.is_superuser:
|
||||
raise PermissionDenied
|
||||
return function(request, *args, **kwargs)
|
||||
|
||||
return _inner
|
||||
94
admin/forms.py
Normal file
94
admin/forms.py
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
from django import forms
|
||||
from django.contrib.auth.models import Group, User
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from accounts.models import UserAttributes
|
||||
|
||||
from .models import Permission
|
||||
|
||||
|
||||
class GroupForm(forms.ModelForm):
|
||||
permissions = forms.ModelMultipleChoiceField(
|
||||
widget=forms.CheckboxSelectMultiple,
|
||||
queryset=Permission.objects.filter(content_type__model='permissionset'),
|
||||
required=False,
|
||||
)
|
||||
|
||||
users = forms.ModelMultipleChoiceField(
|
||||
widget=forms.CheckboxSelectMultiple,
|
||||
queryset=User.objects.all(),
|
||||
required=False,
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(GroupForm, self).__init__(*args, **kwargs)
|
||||
instance = getattr(self, 'instance', None)
|
||||
if instance and instance.id:
|
||||
self.fields['users'].initial = self.instance.user_set.all()
|
||||
|
||||
def save_m2m(self):
|
||||
self.instance.user_set.set(self.cleaned_data['users'])
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
instance = super(GroupForm, self).save()
|
||||
self.save_m2m()
|
||||
return instance
|
||||
|
||||
class Meta:
|
||||
model = Group
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class UserForm(forms.ModelForm):
|
||||
user_permissions = forms.ModelMultipleChoiceField(
|
||||
widget=forms.CheckboxSelectMultiple,
|
||||
queryset=Permission.objects.filter(content_type__model='permissionset'),
|
||||
label=_('Permissions'),
|
||||
required=False,
|
||||
)
|
||||
|
||||
groups = forms.ModelMultipleChoiceField(
|
||||
widget=forms.CheckboxSelectMultiple,
|
||||
queryset=Group.objects.all(),
|
||||
label=_('Groups'),
|
||||
required=False,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = [
|
||||
'username',
|
||||
'groups',
|
||||
'first_name',
|
||||
'last_name',
|
||||
'email',
|
||||
'user_permissions',
|
||||
'is_staff',
|
||||
'is_active',
|
||||
'is_superuser',
|
||||
]
|
||||
|
||||
|
||||
class UserCreateForm(UserForm):
|
||||
password = forms.CharField(widget=forms.PasswordInput)
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
fields = [
|
||||
'username',
|
||||
'password',
|
||||
'groups',
|
||||
'first_name',
|
||||
'last_name',
|
||||
'email',
|
||||
'user_permissions',
|
||||
'is_staff',
|
||||
'is_active',
|
||||
'is_superuser',
|
||||
]
|
||||
|
||||
|
||||
class UserAttributesForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = UserAttributes
|
||||
exclude = ['user']
|
||||
30
admin/migrations/0001_initial.py
Normal file
30
admin/migrations/0001_initial.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# Generated by Django 2.2.12 on 2020-05-27 07:01
|
||||
|
||||
import django.contrib.auth.models
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('auth', '0011_update_proxy_permissions'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Permission',
|
||||
fields=[
|
||||
],
|
||||
options={
|
||||
'proxy': True,
|
||||
'indexes': [],
|
||||
'constraints': [],
|
||||
},
|
||||
bases=('auth.permission',),
|
||||
managers=[
|
||||
('objects', django.contrib.auth.models.PermissionManager()),
|
||||
],
|
||||
),
|
||||
]
|
||||
0
admin/migrations/__init__.py
Normal file
0
admin/migrations/__init__.py
Normal file
11
admin/models.py
Normal file
11
admin/models.py
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
from django.contrib.auth.models import Permission as P
|
||||
|
||||
class Permission(P):
|
||||
"""
|
||||
Proxy model to Django Permissions model allows us to override __str__
|
||||
"""
|
||||
def __str__(self):
|
||||
return f'{self.content_type.app_label}: {self.name}'
|
||||
|
||||
class Meta:
|
||||
proxy = True
|
||||
19
admin/templates/admin/common/confirm_delete.html
Normal file
19
admin/templates/admin/common/confirm_delete.html
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{% extends "base.html" %}
|
||||
{% load bootstrap4 %}
|
||||
{% load font_awesome %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{%trans "Delete" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="alert alert-warning">
|
||||
{%trans "Are you sure you want to delete" %} "{{ object }}"?
|
||||
</div>
|
||||
<a class="btn btn-primary" href="javascript:history.back()">{% icon 'times' %} {% trans "Cancel" %}</a>
|
||||
<button type="submit" class="btn btn-danger">
|
||||
{% icon 'check' %} {% trans "Delete" %}
|
||||
</button>
|
||||
</form>
|
||||
{% endblock %}
|
||||
28
admin/templates/admin/common/form.html
Normal file
28
admin/templates/admin/common/form.html
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{% extends "base.html" %}
|
||||
{% load bootstrap4 %}
|
||||
{% load font_awesome %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "User" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<h2 class="page-header">{{ title }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="thumbnail col-sm-10 offset-1">
|
||||
<form id="create-update" action="" method="post">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form form layout='horizontal' %}
|
||||
</form>
|
||||
<div class="form-group float-right">
|
||||
<a class="btn btn-primary" href="javascript:history.back()">{% icon 'times' %} {% trans "Cancel" %}</a>
|
||||
<button type="submit" form="create-update" class="btn btn-success">
|
||||
{% icon 'check' %} {% trans "Save" %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
28
admin/templates/admin/common/list.html
Normal file
28
admin/templates/admin/common/list.html
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{% extends "base.html" %}
|
||||
{% load font_awesome %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{{ title }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if create_url %}
|
||||
<a class="btn btn-success float-right" href="{% url create_url %}">{% icon 'plus' %} {%trans "Create New" %}</a>
|
||||
{% endif %}
|
||||
<table class="table table-hover table-striped">
|
||||
{% for object in object_list %}
|
||||
<tr>
|
||||
<td>{{ object }}
|
||||
<div class="btn-group float-right">
|
||||
<a class="btn btn-success" href="{% url update_url object.id %}">{% icon 'edit' %} {%trans "Edit"%}</a>
|
||||
{% if extra_urls %}
|
||||
{% for url in extra_urls %}
|
||||
<a class="btn btn-primary" href="{% url url.0 object.id %}">{{ url.1 }}</a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<a class="btn btn-danger" href="{% url delete_url object.id %}">{% icon 'times' %} {%trans "Delete" %}</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
{% endblock %}
|
||||
63
admin/templates/admin/group_list.html
Normal file
63
admin/templates/admin/group_list.html
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% load font_awesome %}
|
||||
{% block title %}{% trans "Users" %}{% endblock %}
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<a href="{% url 'admin:group_create' %}" class="btn btn-success btn-header float-right">
|
||||
{% icon 'plus' %}
|
||||
</a>
|
||||
<div class="float-right search">
|
||||
<input id="filter" class="form-control" type="text" placeholder="{% trans "Search" %}">
|
||||
</div>
|
||||
<h1 class="page-header">{% trans "Groups" %}</h1>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'errors_block.html' %}
|
||||
<div class="row">
|
||||
{% if not groups %}
|
||||
<div class="col-lg-12">
|
||||
<div class="alert alert-warning alert-dismissable">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
|
||||
{% icon 'exclamation-triangle '%} <strong>{% trans "Warning" %}:</strong> {% trans "You don't have any groups" %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="col-lg-12">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans "Group Name" %}</th>
|
||||
<th>{% trans "Actions" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="searchable">
|
||||
{% for group in groups %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href=""><strong>{{ group.name }}</strong></a>
|
||||
</td>
|
||||
<td>
|
||||
<div class="float-right btn-group">
|
||||
<a class="btn btn-primary" href="{% url 'admin:group_update' group.id %}" title="{%trans "Edit" %}">
|
||||
{% icon 'pencil' %}
|
||||
</a>
|
||||
<a class="btn btn-danger" href="{% url 'admin:group_delete' group.id %}" title="{%trans "Delete" %}">
|
||||
{% icon 'times' %}
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
{% block script %}
|
||||
<script src="{% static "js/filter-table.js" %}"></script>
|
||||
{% endblock script %}
|
||||
29
admin/templates/admin/user_form.html
Normal file
29
admin/templates/admin/user_form.html
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
{% extends "base.html" %}
|
||||
{% load bootstrap4 %}
|
||||
{% load font_awesome %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "User" %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<h2 class="page-header">{{ title }}</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="thumbnail col-sm-10 offset-1">
|
||||
<form id="create-update" action="" method="post">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form user_form layout='horizontal' %}
|
||||
{% bootstrap_form attributes_form layout='horizontal' %}
|
||||
</form>
|
||||
<div class="form-group float-right">
|
||||
<a class="btn btn-primary" href="javascript:history.back()">{% icon 'times' %} {% trans "Cancel" %}</a>
|
||||
<button type="submit" form="create-update" class="btn btn-success">
|
||||
{% icon 'check' %} {% trans "Save" %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
79
admin/templates/admin/user_list.html
Normal file
79
admin/templates/admin/user_list.html
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% load font_awesome %}
|
||||
{% block title %}{% trans "Users" %}{% endblock %}
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<a href="{% url 'admin:user_create' %}" class="btn btn-success btn-header float-right">
|
||||
{% icon 'plus' %}
|
||||
</a>
|
||||
<div class="float-right search">
|
||||
<input id="filter" class="form-control" type="text" placeholder="{% trans "Search" %}">
|
||||
</div>
|
||||
<h1 class="page-header">{% trans "Users" %}</h1>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'errors_block.html' %}
|
||||
<div class="row">
|
||||
{% if not users %}
|
||||
<div class="col-lg-12">
|
||||
<div class="alert alert-warning alert-dismissable">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
|
||||
{% icon 'exclamation-triangle '%} <strong>{% trans "Warning" %}:</strong> {% trans "You don't have any users" %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="col-lg-12">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">{% trans "Username" %}</th>
|
||||
<th scope="col">{% trans "Status" %}</th>
|
||||
<th scope="col">{% trans "Staff" %}</th>
|
||||
<th scope="col">{% trans "Superuser" %}</th>
|
||||
<th scope="col">{% trans "Clone" %}</th>
|
||||
<th scope="col">{% trans "" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="searchable">
|
||||
{% for user in users %}
|
||||
<tr class="{% if not user.is_active %}danger{% endif %}">
|
||||
<td>
|
||||
{{ user.username }}
|
||||
</td>
|
||||
<td>
|
||||
{% if user.is_active %}
|
||||
{% trans "Active" %}
|
||||
{% else %}
|
||||
{% trans "Blocked" %}
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{% if user.is_staff %}{% icon 'check' %}{% endif %}</td>
|
||||
<td>{% if user.is_superuser %}{% icon 'check' %}</span>{% endif %}</td>
|
||||
<td>{% if user.userattributes.can_clone_instances %}{% icon 'check' %}{% endif %}</td>
|
||||
<td>
|
||||
<div class="float-right btn-group">
|
||||
<a class="btn btn-success" title="{%trans "View Profile" %}" href="{% url 'account' user.id %}">{% icon 'eye' %}</a>
|
||||
<a class="btn btn-primary" title="{%trans "Edit" %}" href="{% url 'admin:user_update' user.id %}">{% icon 'pencil' %}</a>
|
||||
{% if user.is_active %}
|
||||
<a class="btn btn-warning" title="{%trans "Block" %}" href="{% url 'admin:user_block' user.id %}">{% icon 'stop' %}</a>
|
||||
{% else %}
|
||||
<a class="btn btn-success" title="{%trans "Unblock" %}" href="{% url 'admin:user_unblock' user.id %}">{% icon 'play' %}</a>
|
||||
{% endif %}
|
||||
<a class="btn btn-danger" title="{%trans "Delete" %}" href="{% url 'admin:user_delete' user.id %}">{% icon 'times' %}</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock content %}
|
||||
|
||||
{% block script %}
|
||||
<script src="{% static "js/filter-table.js" %}"></script>
|
||||
{% endblock script %}
|
||||
18
admin/urls.py
Normal file
18
admin/urls.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
from django.urls import path
|
||||
from django.contrib.auth.views import PasswordChangeView, PasswordChangeDoneView
|
||||
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path('groups/', views.group_list, name='group_list'),
|
||||
path('groups/create/', views.group_create, name='group_create'),
|
||||
path('groups/<int:pk>/update/', views.group_update, name='group_update'),
|
||||
path('groups/<int:pk>/delete/', views.group_delete, name='group_delete'),
|
||||
path('users/', views.user_list, name='user_list'),
|
||||
path('users/create/', views.user_create, name='user_create'),
|
||||
path('users/<int:pk>/update/', views.user_update, name='user_update'),
|
||||
path('users/<int:pk>/delete/', views.user_delete, name='user_delete'),
|
||||
path('users/<int:pk>/block/', views.user_block, name='user_block'),
|
||||
path('users/<int:pk>/unblock/', views.user_unblock, name='user_unblock'),
|
||||
path('logs/', views.logs, name='logs'),
|
||||
]
|
||||
172
admin/views.py
Normal file
172
admin/views.py
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
|
||||
from django.contrib.auth.decorators import user_passes_test
|
||||
from django.contrib.auth.models import Group, User
|
||||
from django.core.paginator import Paginator
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from appsettings.models import AppSettings
|
||||
from accounts.models import UserAttributes
|
||||
from logs.models import Logs
|
||||
|
||||
from . import forms
|
||||
from .decorators import superuser_only
|
||||
|
||||
|
||||
@superuser_only
|
||||
def group_list(request):
|
||||
groups = Group.objects.all()
|
||||
return render(
|
||||
request,
|
||||
'admin/group_list.html',
|
||||
{
|
||||
'groups': groups,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@superuser_only
|
||||
def group_create(request):
|
||||
form = forms.GroupForm(request.POST or None)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
return redirect('admin:group_list')
|
||||
return render(
|
||||
request,
|
||||
'admin/common/form.html',
|
||||
{
|
||||
'form': form,
|
||||
'title': _('Create Group'),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@superuser_only
|
||||
def group_update(request, pk):
|
||||
group = get_object_or_404(Group, pk=pk)
|
||||
form = forms.GroupForm(request.POST or None, instance=group)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
return redirect('admin:group_list')
|
||||
|
||||
return render(
|
||||
request,
|
||||
'admin/common/form.html',
|
||||
{
|
||||
'form': form,
|
||||
'title': _('Update Group'),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@superuser_only
|
||||
def group_delete(request, pk):
|
||||
group = get_object_or_404(Group, pk=pk)
|
||||
if request.method == 'POST':
|
||||
group.delete()
|
||||
return redirect('admin:group_list')
|
||||
|
||||
return render(
|
||||
request,
|
||||
'admin/common/confirm_delete.html',
|
||||
{'object': group},
|
||||
)
|
||||
|
||||
|
||||
@superuser_only
|
||||
def user_list(request):
|
||||
users = User.objects.all()
|
||||
return render(
|
||||
request,
|
||||
'admin/user_list.html',
|
||||
{
|
||||
'users': users,
|
||||
'title': _('Users'),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@superuser_only
|
||||
def user_create(request):
|
||||
user_form = forms.UserCreateForm(request.POST or None)
|
||||
attributes_form = forms.UserAttributesForm(request.POST or None)
|
||||
if user_form.is_valid() and attributes_form.is_valid():
|
||||
user = user_form.save()
|
||||
password = user_form.cleaned_data['password']
|
||||
user.set_password(password)
|
||||
user.save()
|
||||
attributes = attributes_form.save(commit=False)
|
||||
attributes.user = user
|
||||
attributes.save()
|
||||
return redirect('admin:user_list')
|
||||
|
||||
return render(
|
||||
request,
|
||||
'admin/user_form.html',
|
||||
{
|
||||
'user_form': user_form,
|
||||
'attributes_form': attributes_form,
|
||||
'title': _('Create User')
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@superuser_only
|
||||
def user_update(request, pk):
|
||||
user = get_object_or_404(User, pk=pk)
|
||||
attributes = UserAttributes.objects.get(user=user)
|
||||
user_form = forms.UserForm(request.POST or None, instance=user)
|
||||
attributes_form = forms.UserAttributesForm(request.POST or None, instance=attributes)
|
||||
if user_form.is_valid() and attributes_form.is_valid():
|
||||
user_form.save()
|
||||
attributes_form.save()
|
||||
return redirect('admin:user_list')
|
||||
|
||||
return render(
|
||||
request,
|
||||
'admin/user_form.html',
|
||||
{
|
||||
'user_form': user_form,
|
||||
'attributes_form': attributes_form,
|
||||
'title': _('Update User')
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@superuser_only
|
||||
def user_delete(request, pk):
|
||||
user = get_object_or_404(User, pk=pk)
|
||||
if request.method == 'POST':
|
||||
user.delete()
|
||||
return redirect('admin:user_list')
|
||||
|
||||
return render(
|
||||
request,
|
||||
'admin/common/confirm_delete.html',
|
||||
{'object': user},
|
||||
)
|
||||
|
||||
|
||||
@superuser_only
|
||||
def user_block(request, pk):
|
||||
user: User = get_object_or_404(User, pk=pk)
|
||||
user.is_active = False
|
||||
user.save()
|
||||
return redirect('admin:user_list')
|
||||
|
||||
|
||||
@superuser_only
|
||||
def user_unblock(request, pk):
|
||||
user: User = get_object_or_404(User, pk=pk)
|
||||
user.is_active = True
|
||||
user.save()
|
||||
return redirect('admin:user_list')
|
||||
|
||||
|
||||
@superuser_only
|
||||
def logs(request):
|
||||
l = Logs.objects.order_by('-date')
|
||||
paginator = Paginator(l, int(AppSettings.objects.get(key="LOGS_PER_PAGE").value))
|
||||
page = request.GET.get('page', 1)
|
||||
logs = paginator.page(page)
|
||||
return render(request, 'admin/logs.html', {'logs': logs})
|
||||
|
|
@ -10,38 +10,37 @@ from computes.models import Compute
|
|||
from computes.forms import ComputeAddTcpForm, ComputeAddSshForm, ComputeEditHostForm, ComputeAddTlsForm, ComputeAddSocketForm
|
||||
from vrtManager.hostdetails import wvmHostDetails
|
||||
from vrtManager.connection import CONN_SSH, CONN_TCP, CONN_TLS, CONN_SOCKET, connection_manager, wvmConnect
|
||||
from admin.decorators import superuser_only
|
||||
|
||||
|
||||
@superuser_only
|
||||
def computes(request):
|
||||
"""
|
||||
:param request:
|
||||
:return:
|
||||
"""
|
||||
|
||||
if not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
def get_hosts_status(computes):
|
||||
"""
|
||||
Function return all hosts all vds on host
|
||||
"""
|
||||
compute_data = []
|
||||
for compute in computes:
|
||||
compute_data.append({'id': compute.id,
|
||||
'name': compute.name,
|
||||
'hostname': compute.hostname,
|
||||
'status': connection_manager.host_is_up(compute.type, compute.hostname),
|
||||
'type': compute.type,
|
||||
'login': compute.login,
|
||||
'password': compute.password,
|
||||
'details': compute.details
|
||||
})
|
||||
compute_data.append({
|
||||
'id': compute.id,
|
||||
'name': compute.name,
|
||||
'hostname': compute.hostname,
|
||||
'status': connection_manager.host_is_up(compute.type, compute.hostname),
|
||||
'type': compute.type,
|
||||
'login': compute.login,
|
||||
'password': compute.password,
|
||||
'details': compute.details
|
||||
})
|
||||
return compute_data
|
||||
|
||||
error_messages = []
|
||||
computes = Compute.objects.filter().order_by('name')
|
||||
computes_info = get_hosts_status(computes)
|
||||
|
||||
|
||||
if request.method == 'POST':
|
||||
if 'host_del' in request.POST:
|
||||
compute_id = request.POST.get('host_id', '')
|
||||
|
|
@ -133,6 +132,7 @@ def computes(request):
|
|||
return render(request, 'computes.html', locals())
|
||||
|
||||
|
||||
@superuser_only
|
||||
def overview(request, compute_id):
|
||||
"""
|
||||
:param request:
|
||||
|
|
@ -140,18 +140,17 @@ def overview(request, compute_id):
|
|||
:return:
|
||||
"""
|
||||
|
||||
if not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
error_messages = []
|
||||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
status = 'true' if connection_manager.host_is_up(compute.type, compute.hostname) is True else 'false'
|
||||
|
||||
try:
|
||||
conn = wvmHostDetails(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type)
|
||||
conn = wvmHostDetails(
|
||||
compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type,
|
||||
)
|
||||
hostname, host_arch, host_memory, logical_cpu, model_cpu, uri_conn = conn.get_node_info()
|
||||
hypervisor = conn.get_hypervisors_domain_types()
|
||||
mem_usage = conn.get_memory_usage()
|
||||
|
|
@ -173,10 +172,12 @@ def compute_graph(request, compute_id):
|
|||
"""
|
||||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
try:
|
||||
conn = wvmHostDetails(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type)
|
||||
conn = wvmHostDetails(
|
||||
compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type,
|
||||
)
|
||||
current_time = timezone.now().strftime("%H:%M:%S")
|
||||
cpu_usage = conn.get_cpu_usage()
|
||||
mem_usage = conn.get_memory_usage()
|
||||
|
|
@ -186,9 +187,11 @@ def compute_graph(request, compute_id):
|
|||
mem_usage = {'usage': 0}
|
||||
current_time = 0
|
||||
|
||||
data = json.dumps({'cpudata': cpu_usage['usage'],
|
||||
'memdata': mem_usage,
|
||||
'timeline': current_time})
|
||||
data = json.dumps({
|
||||
'cpudata': cpu_usage['usage'],
|
||||
'memdata': mem_usage,
|
||||
'timeline': current_time,
|
||||
})
|
||||
response = HttpResponse()
|
||||
response['Content-Type'] = "text/javascript"
|
||||
response.write(data)
|
||||
|
|
@ -207,10 +210,12 @@ def get_compute_disk_buses(request, compute_id, arch, machine, disk):
|
|||
data = dict()
|
||||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
try:
|
||||
conn = wvmConnect(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type)
|
||||
conn = wvmConnect(
|
||||
compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type,
|
||||
)
|
||||
|
||||
disk_device_types = conn.get_disk_device_types(arch, machine)
|
||||
|
||||
|
|
@ -239,10 +244,12 @@ def get_compute_machine_types(request, compute_id, arch):
|
|||
data = dict()
|
||||
try:
|
||||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
conn = wvmConnect(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type)
|
||||
conn = wvmConnect(
|
||||
compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type,
|
||||
)
|
||||
data['machines'] = conn.get_machine_types(arch)
|
||||
except libvirtError:
|
||||
pass
|
||||
|
|
@ -261,10 +268,12 @@ def get_compute_video_models(request, compute_id, arch, machine):
|
|||
data = dict()
|
||||
try:
|
||||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
conn = wvmConnect(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type)
|
||||
conn = wvmConnect(
|
||||
compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type,
|
||||
)
|
||||
data['videos'] = conn.get_video_models(arch, machine)
|
||||
except libvirtError:
|
||||
pass
|
||||
|
|
@ -283,10 +292,12 @@ def get_dom_capabilities(request, compute_id, arch, machine):
|
|||
data = dict()
|
||||
try:
|
||||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
conn = wvmConnect(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type)
|
||||
conn = wvmConnect(
|
||||
compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type,
|
||||
)
|
||||
data['videos'] = conn.get_disk_device_types(arch, machine)
|
||||
data['bus'] = conn.get_disk_device_types(arch, machine)
|
||||
except libvirtError:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
Django==2.2.12
|
||||
django-bootstrap4
|
||||
django-fa==1.0.0
|
||||
django-login-required-middleware==0.5.0
|
||||
gunicorn==20.0.4
|
||||
libsass
|
||||
|
|
|
|||
|
|
@ -12,17 +12,17 @@ from instances.models import Instance
|
|||
from vrtManager.create import wvmCreate
|
||||
from vrtManager import util
|
||||
from logs.views import addlogmsg
|
||||
from admin.decorators import superuser_only
|
||||
|
||||
from webvirtcloud.settings import QEMU_CONSOLE_LISTEN_ADDRESSES
|
||||
|
||||
|
||||
@superuser_only
|
||||
def create_instance_select_type(request, compute_id):
|
||||
"""
|
||||
:param request:
|
||||
:param compute_id:
|
||||
:return:
|
||||
"""
|
||||
if not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
conn = None
|
||||
error_messages = list()
|
||||
|
|
@ -34,10 +34,7 @@ def create_instance_select_type(request, compute_id):
|
|||
appsettings = AppSettings.objects.all()
|
||||
|
||||
try:
|
||||
conn = wvmCreate(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type)
|
||||
conn = wvmCreate(compute.hostname, compute.login, compute.password, compute.type)
|
||||
instances = conn.get_instances()
|
||||
all_hypervisors = conn.get_hypervisors_machines()
|
||||
# Supported hypervisors by webvirtcloud: i686, x86_64(for now)
|
||||
|
|
@ -69,6 +66,7 @@ def create_instance_select_type(request, compute_id):
|
|||
return render(request, 'create_instance_w1.html', locals())
|
||||
|
||||
|
||||
@superuser_only
|
||||
def create_instance(request, compute_id, arch, machine):
|
||||
"""
|
||||
:param request:
|
||||
|
|
@ -77,8 +75,6 @@ def create_instance(request, compute_id, arch, machine):
|
|||
:param machine:
|
||||
:return:
|
||||
"""
|
||||
if not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
conn = None
|
||||
error_messages = list()
|
||||
|
|
@ -92,10 +88,7 @@ def create_instance(request, compute_id, arch, machine):
|
|||
appsettings = AppSettings.objects.all()
|
||||
|
||||
try:
|
||||
conn = wvmCreate(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type)
|
||||
conn = wvmCreate(compute.hostname, compute.login, compute.password, compute.type)
|
||||
|
||||
default_firmware = appsettings.get(key="INSTANCE_FIRMWARE_DEFAULT_TYPE").value
|
||||
default_cpu_mode = appsettings.get(key="INSTANCE_CPU_DEFAULT_MODE").value
|
||||
|
|
@ -150,10 +143,7 @@ def create_instance(request, compute_id, arch, machine):
|
|||
form = FlavorAddForm(request.POST)
|
||||
if form.is_valid():
|
||||
data = form.cleaned_data
|
||||
create_flavor = Flavor(label=data['label'],
|
||||
vcpu=data['vcpu'],
|
||||
memory=data['memory'],
|
||||
disk=data['disk'])
|
||||
create_flavor = Flavor(label=data['label'], vcpu=data['vcpu'], memory=data['memory'], disk=data['disk'])
|
||||
create_flavor.save()
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
if 'delete_flavor' in request.POST:
|
||||
|
|
@ -184,8 +174,14 @@ def create_instance(request, compute_id, arch, machine):
|
|||
error_messages.append(error_msg)
|
||||
else:
|
||||
try:
|
||||
path = conn.create_volume(data['storage'], data['name'], data['hdd_size'], default_disk_format,
|
||||
meta_prealloc, default_disk_owner_uid, default_disk_owner_gid)
|
||||
path = conn.create_volume(
|
||||
data['storage'],
|
||||
data['name'],
|
||||
data['hdd_size'],
|
||||
default_disk_format,
|
||||
meta_prealloc,
|
||||
default_disk_owner_uid,
|
||||
default_disk_owner_gid)
|
||||
volume = dict()
|
||||
volume['device'] = 'disk'
|
||||
volume['path'] = path
|
||||
|
|
@ -210,7 +206,13 @@ def create_instance(request, compute_id, arch, machine):
|
|||
error_msg = _("Image has already exist. Please check volumes or change instance name")
|
||||
error_messages.append(error_msg)
|
||||
else:
|
||||
clone_path = conn.clone_from_template(data['name'], templ_path, data['storage'], meta_prealloc, default_disk_owner_uid, default_disk_owner_gid)
|
||||
clone_path = conn.clone_from_template(
|
||||
data['name'],
|
||||
templ_path,
|
||||
data['storage'],
|
||||
meta_prealloc,
|
||||
default_disk_owner_uid,
|
||||
default_disk_owner_gid)
|
||||
volume = dict()
|
||||
volume['path'] = clone_path
|
||||
volume['type'] = conn.get_volume_type(clone_path)
|
||||
|
|
@ -258,22 +260,32 @@ def create_instance(request, compute_id, arch, machine):
|
|||
firmware["readonly"] = 'yes'
|
||||
firmware["type"] = 'pflash'
|
||||
if 'secboot' in firmware["loader"] and machine != 'q35':
|
||||
messages.warning(request, "Changing machine type from '%s' to 'q35' "
|
||||
"which is required for UEFI secure boot." % machine)
|
||||
messages.warning(
|
||||
request, "Changing machine type from '%s' to 'q35' "
|
||||
"which is required for UEFI secure boot." % machine)
|
||||
machine = 'q35'
|
||||
firmware["secure"] = 'yes'
|
||||
|
||||
if not error_messages:
|
||||
uuid = util.randomUUID()
|
||||
try:
|
||||
conn.create_instance(name=data['name'], memory=data['memory'], vcpu=data['vcpu'],
|
||||
vcpu_mode=data['vcpu_mode'], uuid=uuid, arch=arch, machine=machine,
|
||||
conn.create_instance(name=data['name'],
|
||||
memory=data['memory'],
|
||||
vcpu=data['vcpu'],
|
||||
vcpu_mode=data['vcpu_mode'],
|
||||
uuid=uuid,
|
||||
arch=arch,
|
||||
machine=machine,
|
||||
firmware=firmware,
|
||||
volumes=volume_list,
|
||||
networks=data['networks'], virtio=data['virtio'],
|
||||
listen_addr=data["listener_addr"], nwfilter=data["nwfilter"],
|
||||
graphics=data["graphics"], video=data["video"],
|
||||
console_pass=data["console_pass"], mac=data['mac'],
|
||||
networks=data['networks'],
|
||||
virtio=data['virtio'],
|
||||
listen_addr=data["listener_addr"],
|
||||
nwfilter=data["nwfilter"],
|
||||
graphics=data["graphics"],
|
||||
video=data["video"],
|
||||
console_pass=data["console_pass"],
|
||||
mac=data['mac'],
|
||||
qemu_ga=data['qemu_ga'])
|
||||
create_instance = Instance(compute_id=compute_id, name=data['name'], uuid=uuid)
|
||||
create_instance.save()
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@ from libvirt import libvirtError
|
|||
from computes.models import Compute
|
||||
from interfaces.forms import AddInterface
|
||||
from vrtManager.interface import wvmInterface, wvmInterfaces
|
||||
from admin.decorators import superuser_only
|
||||
|
||||
|
||||
@superuser_only
|
||||
def interfaces(request, compute_id):
|
||||
"""
|
||||
:param request:
|
||||
|
|
@ -14,18 +16,12 @@ def interfaces(request, compute_id):
|
|||
:return:
|
||||
"""
|
||||
|
||||
if not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
ifaces_all = []
|
||||
error_messages = []
|
||||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
|
||||
try:
|
||||
conn = wvmInterfaces(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type)
|
||||
conn = wvmInterfaces(compute.hostname, compute.login, compute.password, compute.type)
|
||||
ifaces = conn.get_ifaces()
|
||||
try:
|
||||
netdevs = conn.get_net_devices()
|
||||
|
|
@ -40,10 +36,15 @@ def interfaces(request, compute_id):
|
|||
form = AddInterface(request.POST)
|
||||
if form.is_valid():
|
||||
data = form.cleaned_data
|
||||
conn.create_iface(data['name'], data['itype'], data['start_mode'], data['netdev'],
|
||||
data['ipv4_type'], data['ipv4_addr'], data['ipv4_gw'],
|
||||
data['ipv6_type'], data['ipv6_addr'], data['ipv6_gw'],
|
||||
data['stp'], data['delay'])
|
||||
conn.create_iface(
|
||||
data['name'],
|
||||
data['itype'],
|
||||
data['start_mode'],
|
||||
data['netdev'],
|
||||
data['ipv4_type'], data['ipv4_addr'], data['ipv4_gw'],
|
||||
data['ipv6_type'], data['ipv6_addr'], data['ipv6_gw'],
|
||||
data['stp'],
|
||||
data['delay'])
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
else:
|
||||
for msg_err in form.errors.values():
|
||||
|
|
@ -55,6 +56,7 @@ def interfaces(request, compute_id):
|
|||
return render(request, 'interfaces.html', locals())
|
||||
|
||||
|
||||
@superuser_only
|
||||
def interface(request, compute_id, iface):
|
||||
"""
|
||||
:param request:
|
||||
|
|
@ -63,19 +65,12 @@ def interface(request, compute_id, iface):
|
|||
:return:
|
||||
"""
|
||||
|
||||
if not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
ifaces_all = []
|
||||
error_messages = []
|
||||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
|
||||
try:
|
||||
conn = wvmInterface(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type,
|
||||
iface)
|
||||
conn = wvmInterface(compute.hostname, compute.login, compute.password, compute.type, iface)
|
||||
start_mode = conn.get_start_mode()
|
||||
state = conn.is_active()
|
||||
mac = conn.get_mac()
|
||||
|
|
|
|||
|
|
@ -2,7 +2,5 @@ from django.urls import path, re_path
|
|||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.showlogs, name='showlogs'),
|
||||
path('<int:page>/', views.showlogs, name='showlogspage'),
|
||||
path('vm_logs/<vname>/', views.vm_logs, name='vm_logs'),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import json
|
||||
from django.shortcuts import render
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.shortcuts import render
|
||||
from django.urls import reverse
|
||||
from appsettings.models import AppSettings
|
||||
|
||||
from admin.decorators import superuser_only
|
||||
from instances.models import Instance
|
||||
from logs.models import Logs
|
||||
|
||||
|
|
@ -18,36 +19,13 @@ def addlogmsg(user, instance, message):
|
|||
add_log_msg.save()
|
||||
|
||||
|
||||
def showlogs(request, page=1):
|
||||
"""
|
||||
:param request:
|
||||
:param page:
|
||||
:return:
|
||||
"""
|
||||
|
||||
if not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
page = int(page)
|
||||
logs_per_page = int(AppSettings.objects.get(key="LOGS_PER_PAGE").value)
|
||||
limit_from = (page-1) * logs_per_page
|
||||
limit_to = page * logs_per_page
|
||||
logs = Logs.objects.all().order_by('-date')[limit_from:limit_to+1]
|
||||
has_next_page = logs.count() > logs_per_page
|
||||
# TODO: remove last element from queryset, but do not affect database
|
||||
|
||||
return render(request, 'showlogs.html', locals())
|
||||
|
||||
|
||||
@superuser_only
|
||||
def vm_logs(request, vname):
|
||||
"""
|
||||
:param request:
|
||||
:param vname:
|
||||
:return:
|
||||
"""
|
||||
|
||||
if not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
vm = Instance.objects.get(name=vname)
|
||||
logs_ = Logs.objects.filter(instance=vm.name, date__gte=vm.created).order_by('-date')
|
||||
|
|
@ -59,5 +37,5 @@ def vm_logs(request, vname):
|
|||
log['message'] = l.message
|
||||
log['date'] = l.date.strftime('%x %X')
|
||||
logs.append(log)
|
||||
|
||||
|
||||
return HttpResponse(json.dumps(logs))
|
||||
|
|
|
|||
|
|
@ -1,32 +1,34 @@
|
|||
from django.shortcuts import render, get_object_or_404
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.urls import reverse
|
||||
from django.contrib import messages
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404, render
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from libvirt import libvirtError
|
||||
|
||||
from admin.decorators import superuser_only
|
||||
from computes.models import Compute
|
||||
from networks.forms import AddNetPool
|
||||
from vrtManager.network import wvmNetwork, wvmNetworks
|
||||
from vrtManager.network import network_size
|
||||
from vrtManager.network import network_size, wvmNetwork, wvmNetworks
|
||||
|
||||
|
||||
@superuser_only
|
||||
def networks(request, compute_id):
|
||||
"""
|
||||
:param request:
|
||||
:param compute_id:
|
||||
:return:
|
||||
"""
|
||||
if not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
error_messages = []
|
||||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
|
||||
try:
|
||||
conn = wvmNetworks(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type)
|
||||
conn = wvmNetworks(
|
||||
compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type,
|
||||
)
|
||||
networks = conn.get_networks_info()
|
||||
dhcp4 = netmask4 = gateway4 = ''
|
||||
dhcp6 = prefix6 = gateway6 = ''
|
||||
|
|
@ -51,11 +53,21 @@ def networks(request, compute_id):
|
|||
if prefix6 != '64':
|
||||
error_messages.append(_('For libvirt, the IPv6 network prefix must be /64'))
|
||||
if not error_messages:
|
||||
conn.create_network(data['name'],
|
||||
data['forward'],
|
||||
ipv4, gateway4, netmask4, dhcp4,
|
||||
ipv6, gateway6, prefix6, dhcp6,
|
||||
data['bridge_name'], data['openvswitch'], data['fixed'])
|
||||
conn.create_network(
|
||||
data['name'],
|
||||
data['forward'],
|
||||
ipv4,
|
||||
gateway4,
|
||||
netmask4,
|
||||
dhcp4,
|
||||
ipv6,
|
||||
gateway6,
|
||||
prefix6,
|
||||
dhcp6,
|
||||
data['bridge_name'],
|
||||
data['openvswitch'],
|
||||
data['fixed'],
|
||||
)
|
||||
return HttpResponseRedirect(reverse('network', args=[compute_id, data['name']]))
|
||||
else:
|
||||
for msg_err in form.errors.values():
|
||||
|
|
@ -67,6 +79,7 @@ def networks(request, compute_id):
|
|||
return render(request, 'networks.html', locals())
|
||||
|
||||
|
||||
@superuser_only
|
||||
def network(request, compute_id, pool):
|
||||
"""
|
||||
:param request:
|
||||
|
|
@ -75,18 +88,17 @@ def network(request, compute_id, pool):
|
|||
:return:
|
||||
"""
|
||||
|
||||
if not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
error_messages = []
|
||||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
|
||||
try:
|
||||
conn = wvmNetwork(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type,
|
||||
pool)
|
||||
conn = wvmNetwork(
|
||||
compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type,
|
||||
pool,
|
||||
)
|
||||
networks = conn.get_networks()
|
||||
state = conn.is_active()
|
||||
device = conn.get_bridge_device()
|
||||
|
|
@ -186,8 +198,7 @@ def network(request, compute_id, pool):
|
|||
if edit_xml:
|
||||
conn.edit_network(edit_xml)
|
||||
if conn.is_active():
|
||||
messages.success(request, _("Network XML is changed. \\"
|
||||
"Stop and start network to activate new config."))
|
||||
messages.success(request, _("Network XML is changed. \\" "Stop and start network to activate new config."))
|
||||
else:
|
||||
messages.success(request, _("Network XML is changed."))
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
|
|
@ -200,8 +211,10 @@ def network(request, compute_id, pool):
|
|||
try:
|
||||
conn.set_qos(qos_dir, average, peak, burst)
|
||||
if conn.is_active():
|
||||
messages.success(request, _(f"{qos_dir.capitalize()} QoS is set. Network XML is changed.") +
|
||||
_("Stop and start network to activate new config"))
|
||||
messages.success(
|
||||
request,
|
||||
_(f"{qos_dir.capitalize()} QoS is set. Network XML is changed.") +
|
||||
_("Stop and start network to activate new config"))
|
||||
else:
|
||||
messages.success(request, _("{} QoS is set").format(qos_dir.capitalize()))
|
||||
except libvirtError as lib_err:
|
||||
|
|
@ -212,8 +225,10 @@ def network(request, compute_id, pool):
|
|||
conn.unset_qos(qos_dir)
|
||||
|
||||
if conn.is_active():
|
||||
messages.success(request, _(f"{qos_dir.capitalize()} QoS is deleted. Network XML is changed. ") +
|
||||
_("Stop and start network to activate new config."))
|
||||
messages.success(
|
||||
request,
|
||||
_(f"{qos_dir.capitalize()} QoS is deleted. Network XML is changed. ") +
|
||||
_("Stop and start network to activate new config."))
|
||||
else:
|
||||
messages.success(request, _(f"{qos_dir.capitalize()} QoS is deleted"))
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
|
|
|
|||
|
|
@ -1,15 +1,18 @@
|
|||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import render, get_object_or_404
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.shortcuts import get_object_or_404, render
|
||||
from django.urls import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from libvirt import libvirtError
|
||||
|
||||
from admin.decorators import superuser_only
|
||||
from computes.models import Compute
|
||||
from vrtManager import util
|
||||
from vrtManager.nwfilters import wvmNWFilters, wvmNWFilter
|
||||
from vrtManager.instance import wvmInstances, wvmInstance
|
||||
from logs.views import addlogmsg
|
||||
from vrtManager import util
|
||||
from vrtManager.instance import wvmInstance, wvmInstances
|
||||
from vrtManager.nwfilters import wvmNWFilter, wvmNWFilters
|
||||
|
||||
|
||||
@superuser_only
|
||||
def nwfilters(request, compute_id):
|
||||
"""
|
||||
:param request:
|
||||
|
|
@ -17,18 +20,12 @@ def nwfilters(request, compute_id):
|
|||
:return:
|
||||
"""
|
||||
|
||||
if not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
error_messages = []
|
||||
nwfilters_all = []
|
||||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
|
||||
try:
|
||||
conn = wvmNWFilters(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type)
|
||||
conn = wvmNWFilters(compute.hostname, compute.login, compute.password, compute.type)
|
||||
|
||||
if request.method == 'POST':
|
||||
if 'create_nwfilter' in request.POST:
|
||||
|
|
@ -102,9 +99,11 @@ def nwfilters(request, compute_id):
|
|||
error_messages.append(err)
|
||||
addlogmsg(request.user.username, compute.hostname, err)
|
||||
|
||||
return render(request, 'nwfilters.html', {'error_messages': error_messages,
|
||||
'nwfilters': nwfilters_all,
|
||||
'compute': compute})
|
||||
return render(request, 'nwfilters.html', {
|
||||
'error_messages': error_messages,
|
||||
'nwfilters': nwfilters_all,
|
||||
'compute': compute
|
||||
})
|
||||
|
||||
|
||||
def nwfilter(request, compute_id, nwfltr):
|
||||
|
|
@ -119,15 +118,8 @@ def nwfilter(request, compute_id, nwfltr):
|
|||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
|
||||
try:
|
||||
nwfilter = wvmNWFilter(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type,
|
||||
nwfltr)
|
||||
conn = wvmNWFilters(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type)
|
||||
nwfilter = wvmNWFilter(compute.hostname, compute.login, compute.password, compute.type, nwfltr)
|
||||
conn = wvmNWFilters(compute.hostname, compute.login, compute.password, compute.type)
|
||||
|
||||
for nwf in conn.get_nwfilters():
|
||||
nwfilters_all.append(conn.get_nwfilter_info(nwf))
|
||||
|
|
|
|||
|
|
@ -1,60 +1,61 @@
|
|||
{% load i18n %}
|
||||
{% if request.user.is_superuser %}
|
||||
<a href="#AddSecret" type="button" class="btn btn-success float-right" data-toggle="modal">
|
||||
<span class="fa fa-plus" aria-hidden="true"></span>
|
||||
</a>
|
||||
<a href="#AddSecret" type="button" class="btn btn-success float-right" data-toggle="modal">
|
||||
<span class="fa fa-plus" aria-hidden="true"></span>
|
||||
</a>
|
||||
|
||||
<!-- Modal Secret -->
|
||||
<div class="modal fade" id="AddSecret" tabindex="-1" role="dialog" aria-labelledby="AddSecret" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h5 class="modal-title">{% trans "Create New Secret" %}</h5>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method="post" action="" role="form" aria-label="Create Secret form">{% csrf_token %}
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label">{% trans "Ephemeral" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<select name="ephemeral" class="form-control">
|
||||
<option value="no">{% trans "no" %}</option>
|
||||
<option value="yes">{% trans "yes" %}</option>
|
||||
</select>
|
||||
</div>
|
||||
<!-- Modal Secret -->
|
||||
<div class="modal fade" id="AddSecret" tabindex="-1" role="dialog" aria-labelledby="AddSecret" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{% trans "Create New Secret" %}</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method="post" action="" role="form" aria-label="Create Secret form">{% csrf_token %}
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label">{% trans "Ephemeral" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<select name="ephemeral" class="form-control">
|
||||
<option value="no">{% trans "no" %}</option>
|
||||
<option value="yes">{% trans "yes" %}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label">{% trans "Private" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<select name="private" class="form-control">
|
||||
<option value="no">{% trans "no" %}</option>
|
||||
<option value="yes">{% trans "yes" %}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label">{% trans "Usage" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<select name="usage_type" class="form-control">
|
||||
<option value="ceph">{% trans "ceph" %}</option>
|
||||
<option value="volume">{% trans "volume" %}</option>
|
||||
<option value="iscsi">{% trans "iscsi" %}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 col-form-label">{% trans "Data" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="text" name="data" class="form-control" value="" required pattern="[a-z0-9\. ]+"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">{% trans "Close" %}</button>
|
||||
<button type="submit" class="btn btn-primary" name="create">{% trans "Create" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div> <!-- /.modal-content -->
|
||||
</div> <!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label">{% trans "Private" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<select name="private" class="form-control">
|
||||
<option value="no">{% trans "no" %}</option>
|
||||
<option value="yes">{% trans "yes" %}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label">{% trans "Usage" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<select name="usage_type" class="form-control">
|
||||
{% for key, usage_type in secret_usage_types.items %}
|
||||
<option value="{{ usage_type }}">{{ usage_type }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label">{% trans "Data" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="text" name="data" class="form-control" value="" required
|
||||
pattern="[a-z0-9\. ]+" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">{% trans "Close" %}</button>
|
||||
<button type="submit" class="btn btn-primary" name="create">{% trans "Create" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div> <!-- /.modal-content -->
|
||||
</div> <!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
{% endif %}
|
||||
|
|
@ -3,128 +3,129 @@
|
|||
{% load staticfiles %}
|
||||
{% block title %}{% trans "Secrets" %} - {{ compute.name }}{% endblock %}
|
||||
{% block style %}
|
||||
<link rel="stylesheet" href="{% static "css/sortable-theme-bootstrap.css" %}" />
|
||||
<link rel="stylesheet" href="{% static "css/sortable-theme-bootstrap.css" %}" />
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<!-- Page Heading -->
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
{% include 'create_secret_block.html' %}
|
||||
<h2 class="page-header">{% trans "Secrets" %}</h2>
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb bg-light shadow-sm">
|
||||
<li class="breadcrumb-item active">
|
||||
<a href="{% url 'overview' compute.id %}"><i class="fa fa-dashboard"></i> {% trans "Overview" %}</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{% url 'instances' compute.id %}"><i class="fa fa-server"></i> {% trans "Instances" %}</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{% url 'storages' compute.id %}"><i class="fa fa-hdd-o"></i> {% trans "Storages" %}</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{% url 'networks' compute.id %}"><i class="fa fa-sitemap"></i> {% trans "Networks" %}</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{% url 'interfaces' compute.id %}"><i class="fa fa-wifi"></i> {% trans "Interfaces" %}</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{% url 'nwfilters' compute.id %}"><i class="fa fa-filter"></i> {% trans "NWFilters" %}</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item">
|
||||
<span class="font-weight-bold"><i class="fa fa-key"></i> {% trans "Secrets" %}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
<!-- Page Heading -->
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
{% include 'create_secret_block.html' %}
|
||||
<h2 class="page-header">{% trans "Secrets" %}</h2>
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb bg-light shadow-sm">
|
||||
<li class="breadcrumb-item active">
|
||||
<a href="{% url 'overview' compute.id %}"><i class="fa fa-dashboard"></i> {% trans "Overview" %}</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{% url 'instances' compute.id %}"><i class="fa fa-server"></i> {% trans "Instances" %}</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{% url 'storages' compute.id %}"><i class="fa fa-hdd-o"></i> {% trans "Storages" %}</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{% url 'networks' compute.id %}"><i class="fa fa-sitemap"></i> {% trans "Networks" %}</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{% url 'interfaces' compute.id %}"><i class="fa fa-wifi"></i> {% trans "Interfaces" %}</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item">
|
||||
<a href="{% url 'nwfilters' compute.id %}"><i class="fa fa-filter"></i> {% trans "NWFilters" %}</a>
|
||||
</li>
|
||||
<li class="breadcrumb-item">
|
||||
<span class="font-weight-bold"><i class="fa fa-key"></i> {% trans "Secrets" %}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
|
||||
{% include 'errors_block.html' %}
|
||||
|
||||
<div class="row">
|
||||
{% if not secrets_all %}
|
||||
<div class="col-lg-12">
|
||||
<div class="alert alert-warning alert-dismissable shadow-sm">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
|
||||
<i class="fa fa-exclamation-triangle"></i> <strong>{% trans "Warning" %}:</strong>
|
||||
{% trans "Hypervisor doesn't have any Secrets" %}
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
{% else %}
|
||||
<div class="col-lg-12">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover sortable-theme-bootstrap" data-sortable>
|
||||
<thead>
|
||||
<tr class="active">
|
||||
<th scope="col">{% trans "UUID" %}</th>
|
||||
<th scope="col">{% trans "Usage Type" %}</th>
|
||||
<th scope="col">{% trans "Data" %}</th>
|
||||
<th scope="col" data-sortable="false" style="width:90px;">{% trans "Actions" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for secret in secrets_all %}
|
||||
<tr>
|
||||
<th scope="row">{{ secret.uuid }}</th>
|
||||
<td>{{ secret.usageType }}</td>
|
||||
<td>{{ secret.usage }}</td>
|
||||
<td>
|
||||
<form action="" method="post" role="form" aria-label="Delete secret form">{% csrf_token %}
|
||||
<input type="hidden" name="uuid" value="{{ secret.uuid }}" />
|
||||
<a data-toggle="modal" href="#editSecret{{ secret.uuid }}"
|
||||
class="btn btn-sm btn-primary" title="{% trans "Edit" %}">
|
||||
<span class="fa fa-pencil"></span>
|
||||
</a>
|
||||
<button type="submit" class="btn btn-sm btn-danger" name="delete"
|
||||
title="{% trans "Delete" %}"
|
||||
onclick="return confirm('{% trans "Are you sure?" %}')">
|
||||
<span class="fa fa-trash"></span>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
{% include 'errors_block.html' %}
|
||||
|
||||
<div class="row">
|
||||
{% if not secrets_all %}
|
||||
<div class="col-lg-12">
|
||||
<div class="alert alert-warning alert-dismissable shadow-sm">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
|
||||
<i class="fa fa-exclamation-triangle"></i> <strong>{% trans "Warning" %}:</strong> {% trans "Hypervisor doesn't have any Secrets" %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="col-lg-12">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover sortable-theme-bootstrap" data-sortable>
|
||||
<thead>
|
||||
<tr class="active">
|
||||
<th scope="col">{% trans "UUID" %}</th>
|
||||
<th scope="col">{% trans "Type" %}</th>
|
||||
<th scope="col">{% trans "Usage" %}</th>
|
||||
<th scope="col" data-sortable="false" style="width:90px;">{% trans "Action" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for secret in secrets_all %}
|
||||
<tr>
|
||||
<th scope="row">{{ secret.uuid }}</th>
|
||||
<td>{% ifequal secret.usageType 0 %}
|
||||
{% trans "volume" %}
|
||||
{% endifequal %}
|
||||
{% ifequal secret.usageType 1 %}
|
||||
{% trans "iscsi" %}
|
||||
{% endifequal %}
|
||||
{% ifequal secret.usageType 2 %}
|
||||
{% trans "ceph" %}
|
||||
{% endifequal %}
|
||||
</td>
|
||||
<td>{{ secret.usage }}</td>
|
||||
<td>
|
||||
<form action="" method="post" role="form" aria-label="Delete secret form">{% csrf_token %}
|
||||
<input type="hidden" name="uuid" value="{{ secret.uuid }}"/>
|
||||
<a data-toggle="modal" href="#editSecret{{ secret.uuid }}" class="btn btn-sm btn-primary" title="{% trans "Edit" %}">
|
||||
<span class="fa fa-pencil"></span>
|
||||
</a>
|
||||
<button type="submit" class="btn btn-sm btn-danger" name="delete" title="{% trans "Delete" %}" onclick="return confirm('{% trans "Are you sure?" %}')">
|
||||
<span class="fa fa-trash"></span>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="editSecret{{ secret.uuid }}" tabindex="-1" role="dialog"
|
||||
aria-labelledby="editSecret" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{% trans "Set secret value" %}</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<!-- Modal -->
|
||||
<div class="modal fade" id="editSecret{{ secret.uuid }}" tabindex="-1" role="dialog"
|
||||
aria-labelledby="editSecret" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">{% trans "Set secret value" %}</h5>
|
||||
<button type="button" class="close" data-dismiss="modal"
|
||||
aria-hidden="true">×</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method="post" role="form" aria-label="Edit secret form">
|
||||
{% csrf_token %}
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label">{% trans "Value" %}</label>
|
||||
<input type="hidden" name="uuid" value="{{ secret.uuid }}">
|
||||
<div class="col-sm-6">
|
||||
<input type="text" name="value" class="form-control"
|
||||
value="{{ secret.value }}" maxlength="45" required
|
||||
pattern="[a-zA-Z0-9]$+">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method="post" role="form" aria-label="Edit secret form">{% csrf_token %}
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label">{% trans "Value" %}</label>
|
||||
<input type="hidden" name="uuid" value="{{ secret.uuid }}">
|
||||
<div class="col-sm-6">
|
||||
<input type="text" name="value" class="form-control" value="{{ secret.value }}" maxlength="45" required pattern="[a-zA-Z0-9]$+">
|
||||
</div>
|
||||
</div>
|
||||
</div> <!-- /.modal-content -->
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">{% trans "Close" %}</button>
|
||||
<button type="submit" class="btn btn-primary" name="set_value">{% trans "Set" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div> <!-- /.tab-content -->
|
||||
</div> <!-- /.modal-dialog -->
|
||||
</div> <!-- /.modal -->
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div> <!-- /.modal-content -->
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary"
|
||||
data-dismiss="modal">{% trans "Close" %}</button>
|
||||
<button type="submit" class="btn btn-primary"
|
||||
name="set_value">{% trans "Set" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div> <!-- /.tab-content -->
|
||||
</div> <!-- /.modal-dialog -->
|
||||
</div> <!-- /.modal -->
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block script %}
|
||||
<script src="{% static "js/sortable.min.js" %}"></script>
|
||||
<script src="{% static 'js/sortable.min.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
|
@ -1,12 +1,22 @@
|
|||
from django.shortcuts import render, get_object_or_404
|
||||
from secrets.forms import AddSecret
|
||||
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404, render
|
||||
from django.urls import reverse
|
||||
from libvirt import libvirtError
|
||||
from libvirt import VIR_SECRET_USAGE_TYPE_NONE, \
|
||||
VIR_SECRET_USAGE_TYPE_CEPH, \
|
||||
VIR_SECRET_USAGE_TYPE_TLS, \
|
||||
VIR_SECRET_USAGE_TYPE_VOLUME, \
|
||||
VIR_SECRET_USAGE_TYPE_ISCSI
|
||||
|
||||
from admin.decorators import superuser_only
|
||||
|
||||
from computes.models import Compute
|
||||
from secrets.forms import AddSecret
|
||||
from vrtManager.secrets import wvmSecrets
|
||||
|
||||
|
||||
@superuser_only
|
||||
def secrets(request, compute_id):
|
||||
"""
|
||||
:param request:
|
||||
|
|
@ -14,36 +24,44 @@ def secrets(request, compute_id):
|
|||
:return:
|
||||
"""
|
||||
|
||||
if not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
secrets_all = []
|
||||
error_messages = []
|
||||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
secret_usage_types = {
|
||||
VIR_SECRET_USAGE_TYPE_NONE: "none",
|
||||
VIR_SECRET_USAGE_TYPE_VOLUME: "volume",
|
||||
VIR_SECRET_USAGE_TYPE_CEPH: "ceph",
|
||||
VIR_SECRET_USAGE_TYPE_ISCSI: "iscsi",
|
||||
VIR_SECRET_USAGE_TYPE_TLS: "tls",
|
||||
}
|
||||
|
||||
try:
|
||||
conn = wvmSecrets(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type)
|
||||
conn = wvmSecrets(compute.hostname, compute.login,
|
||||
compute.password, compute.type)
|
||||
secrets = conn.get_secrets()
|
||||
|
||||
for uuid in secrets:
|
||||
secrt = conn.get_secret(uuid)
|
||||
try:
|
||||
secret_value = conn.get_secret_value(uuid)
|
||||
secrt_value = conn.get_secret_value(uuid)
|
||||
except libvirtError as lib_err:
|
||||
secret_value = None
|
||||
secrets_all.append({'usage': secrt.usageID(),
|
||||
'uuid': secrt.UUIDString(),
|
||||
'usageType': secrt.usageType(),
|
||||
'value': secret_value
|
||||
})
|
||||
secrets_all.append({
|
||||
'usage': secrt.usageID(),
|
||||
'uuid': secrt.UUIDString(),
|
||||
'usageType': secret_usage_types[secrt.usageType()],
|
||||
'value': secrt_value
|
||||
})
|
||||
if request.method == 'POST':
|
||||
if 'create' in request.POST:
|
||||
form = AddSecret(request.POST)
|
||||
if form.is_valid():
|
||||
data = form.cleaned_data
|
||||
conn.create_secret(data['ephemeral'], data['private'], data['usage_type'], data['data'])
|
||||
conn.create_secret(
|
||||
data['ephemeral'],
|
||||
data['private'],
|
||||
data['usage_type'],
|
||||
data['data'])
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
else:
|
||||
for msg_err in form.errors.values():
|
||||
|
|
@ -55,7 +73,10 @@ def secrets(request, compute_id):
|
|||
if 'set_value' in request.POST:
|
||||
uuid = request.POST.get('uuid', '')
|
||||
value = request.POST.get('value', '')
|
||||
conn.set_secret_value(uuid, value)
|
||||
try:
|
||||
conn.set_secret_value(uuid, value)
|
||||
except Exception as err:
|
||||
error_messages.append(err)
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
except libvirtError as err:
|
||||
error_messages.append(err)
|
||||
|
|
|
|||
|
|
@ -155,3 +155,17 @@ p {
|
|||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.bottom-bar-margin {
|
||||
margin-top: 65px;
|
||||
}
|
||||
|
||||
.thumbnail {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
/* make dropdowns show on hover */
|
||||
@media only screen and (min-width: 768px) {
|
||||
.dropdown:hover .dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
12
static/js/filter-table.js
Normal file
12
static/js/filter-table.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
function filter_table() {
|
||||
var rex = new RegExp($(this).val(), 'i');
|
||||
$('.searchable tr').hide();
|
||||
$('.searchable tr').filter(function () {
|
||||
return rex.test($(this).text());
|
||||
}).show();
|
||||
}
|
||||
$(document).ready(function () {
|
||||
(function ($) {
|
||||
$('#filter').keyup(filter_table)
|
||||
}(jQuery));
|
||||
});
|
||||
|
|
@ -1,33 +1,31 @@
|
|||
import json
|
||||
from django.shortcuts import render, get_object_or_404
|
||||
from django.contrib import messages
|
||||
from django.http import HttpResponseRedirect, HttpResponse
|
||||
from django.shortcuts import render, get_object_or_404
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.urls import reverse
|
||||
from django.contrib import messages
|
||||
from libvirt import libvirtError
|
||||
|
||||
from admin.decorators import superuser_only
|
||||
from computes.models import Compute
|
||||
from appsettings.models import AppSettings
|
||||
from storages.forms import AddStgPool, AddImage, CloneImage
|
||||
from vrtManager.storage import wvmStorage, wvmStorages
|
||||
|
||||
|
||||
@superuser_only
|
||||
def storages(request, compute_id):
|
||||
"""
|
||||
:param request:
|
||||
:param compute_id:
|
||||
:return:
|
||||
"""
|
||||
if not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
error_messages = []
|
||||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
|
||||
try:
|
||||
conn = wvmStorages(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type)
|
||||
conn = wvmStorages(compute.hostname, compute.login, compute.password, compute.type)
|
||||
storages = conn.get_storages_info()
|
||||
secrets = conn.get_secrets()
|
||||
|
||||
|
|
@ -48,12 +46,10 @@ def storages(request, compute_id):
|
|||
error_messages.append(msg)
|
||||
if not error_messages:
|
||||
if data['stg_type'] == 'rbd':
|
||||
conn.create_storage_ceph(data['stg_type'], data['name'],
|
||||
data['ceph_pool'], data['ceph_host'],
|
||||
conn.create_storage_ceph(data['stg_type'], data['name'], data['ceph_pool'], data['ceph_host'],
|
||||
data['ceph_user'], data['secret'])
|
||||
elif data['stg_type'] == 'netfs':
|
||||
conn.create_storage_netfs(data['stg_type'], data['name'],
|
||||
data['netfs_host'], data['source'],
|
||||
conn.create_storage_netfs(data['stg_type'], data['name'], data['netfs_host'], data['source'],
|
||||
data['source_format'], data['target'])
|
||||
else:
|
||||
conn.create_storage(data['stg_type'], data['name'], data['source'], data['target'])
|
||||
|
|
@ -68,6 +64,7 @@ def storages(request, compute_id):
|
|||
return render(request, 'storages.html', locals())
|
||||
|
||||
|
||||
@superuser_only
|
||||
def storage(request, compute_id, pool):
|
||||
"""
|
||||
:param request:
|
||||
|
|
@ -75,10 +72,6 @@ def storage(request, compute_id, pool):
|
|||
:param pool:
|
||||
:return:
|
||||
"""
|
||||
|
||||
if not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
def handle_uploaded_file(path, f_name):
|
||||
target = path + '/' + str(f_name)
|
||||
destination = open(target, 'wb+')
|
||||
|
|
@ -91,11 +84,7 @@ def storage(request, compute_id, pool):
|
|||
meta_prealloc = False
|
||||
|
||||
try:
|
||||
conn = wvmStorage(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type,
|
||||
pool)
|
||||
conn = wvmStorage(compute.hostname, compute.login, compute.password, compute.type, pool)
|
||||
|
||||
storages = conn.get_storages()
|
||||
state = conn.is_active()
|
||||
|
|
@ -226,11 +215,7 @@ def get_volumes(request, compute_id, pool):
|
|||
data = {}
|
||||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
try:
|
||||
conn = wvmStorage(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type,
|
||||
pool)
|
||||
conn = wvmStorage(compute.hostname, compute.login, compute.password, compute.type, pool)
|
||||
conn.refresh()
|
||||
data['vols'] = sorted(conn.get_volumes())
|
||||
except libvirtError:
|
||||
|
|
|
|||
15
templates/403.html
Normal file
15
templates/403.html
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{% extends "base_auth.html" %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "403" %}{% endblock %}
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-12 text-center">
|
||||
<h1>{% trans 'Oops!'%}</h1>
|
||||
|
||||
<p class="lead">{% trans "403 Forbidden" %}</p>
|
||||
|
||||
<p>{% trans "You do not have permission to access this page." %}</p>
|
||||
<a class="btn btn-success" href="javascript:history.back()">← {% trans 'Back'%}</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
{% load i18n %}
|
||||
{% load tags_active %}
|
||||
{% load font_awesome %}
|
||||
{% load common_tags %}
|
||||
<!-- Fixed navbar -->
|
||||
<nav class="navbar navbar-expand-md navbar-dark bg-primary mb-3" aria-label="Main top navbar">
|
||||
<div class="container">
|
||||
|
|
@ -10,26 +11,27 @@
|
|||
|
||||
<div id="navbar" class="collapse navbar-collapse">
|
||||
<ul class="navbar-nav mr-auto mt-2 mt-md-0">
|
||||
<li class="nav-item {% class_active request "^/instance" %}">
|
||||
<a class="nav-link" href="{% url 'allinstances' %}"><i class="fa fa-fw fa-desktop"></i> {% trans "Instances" %}</a>
|
||||
<li class="nav-item {% class_active request '^/instances' %}">
|
||||
<a class="nav-link" href="{% url 'allinstances' %}"><i class="fa fa-fw fa-desktop"></i> {% trans "Instances" %}</a>
|
||||
</li>
|
||||
{% if request.user.is_superuser %}
|
||||
<li class="nav-item {% class_active request "^/compute" %}
|
||||
{% class_active request "^/create" %}">
|
||||
<a class="nav-link" href="{% url 'computes' %}"><i class="fa fa-fw fa-server"></i> {% trans "Computes" %}</a>
|
||||
</li>
|
||||
<li class="nav-item {% class_active request "^/account" %}">
|
||||
<a class="nav-link" href="{% url 'accounts' %}"><i class="fa fa-fw fa-users"></i> {% trans "Users" %}</a>
|
||||
</li>
|
||||
<li class="nav-item {% class_active request "^/log" %}">
|
||||
<a class="nav-link" href="{% url 'showlogs' %}"><i class="fa fa-fw fa-list-alt"></i> {% trans "Logs" %}</a>
|
||||
</li>
|
||||
<li class="nav-item {% class_active request '^/computes' %}">
|
||||
<a class="nav-link" href="{% url 'computes' %}"><i class="fa fa-fw fa-server"></i> {% trans "Computes" %}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
<ul class="navbar-nav navbar-right">
|
||||
<ul class="navbar-nav navbar-right mt-2 mt-md-0">
|
||||
{% if request.user.is_superuser %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'appsettings' %}"><i class="fa fa-wrench"></i></a>
|
||||
<li class="nav-item dropdown {% app_active request 'admin' %}">
|
||||
<a class="nav-link" id="administration" href="#" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
{% icon 'wrench' %}
|
||||
</a>
|
||||
<div class="dropdown-menu" aria-labelledby="administration">
|
||||
<a class="dropdown-item {% view_active request 'admin:user_list' %}" href="{% url 'admin:user_list' %}">{% icon 'user-plus' %} {% trans "Users" %}</a>
|
||||
<a class="dropdown-item {% view_active request 'admin:group_list' %}" href="{% url 'admin:group_list' %}">{% icon 'users' %} {% trans "Groups" %}</a>
|
||||
<a class="dropdown-item {% view_active request 'admin:logs' %}" href="{% url 'admin:logs' %}">{% icon 'list-alt' %} {% trans "Logs" %}</a>
|
||||
<a class="dropdown-item {% view_active request 'appsettings' %}" href="{% url 'appsettings' %}">{% icon 'cogs' %} {% trans "Settings" %}</a>
|
||||
</div>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="nav-item dropdown">
|
||||
|
|
@ -41,9 +43,9 @@
|
|||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="{% url 'logout' %}"><i class="fa fa-fw fa-power-off"></i> {% trans "Log Out" %}</a>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</nav>
|
||||
26
webvirtcloud/common_tags.py
Normal file
26
webvirtcloud/common_tags.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
from django import template
|
||||
import re
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def app_active(request, app_name):
|
||||
if request.resolver_match.app_name == app_name:
|
||||
return 'active'
|
||||
return ''
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def view_active(request, view_name):
|
||||
if request.resolver_match.view_name == view_name:
|
||||
return 'active'
|
||||
return ''
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def class_active(request, pattern):
|
||||
if re.search(pattern, request.path):
|
||||
# Not sure why 'class="active"' returns class=""active""
|
||||
return 'active'
|
||||
return ''
|
||||
|
|
@ -14,17 +14,19 @@ DEBUG = True
|
|||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'bootstrap4',
|
||||
'fa',
|
||||
'accounts',
|
||||
'admin',
|
||||
'appsettings',
|
||||
'computes',
|
||||
'console',
|
||||
'create',
|
||||
|
|
@ -35,7 +37,6 @@ INSTALLED_APPS = [
|
|||
'nwfilters',
|
||||
'storages',
|
||||
'secrets',
|
||||
'appsettings',
|
||||
'logs',
|
||||
]
|
||||
|
||||
|
|
@ -57,7 +58,9 @@ ROOT_URLCONF = 'webvirtcloud.urls'
|
|||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [ os.path.join(BASE_DIR, 'templates'), ],
|
||||
'DIRS': [
|
||||
os.path.join(BASE_DIR, 'templates'),
|
||||
],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
|
|
@ -66,13 +69,15 @@ TEMPLATES = [
|
|||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
],
|
||||
'libraries': {
|
||||
'common_tags': 'webvirtcloud.common_tags',
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'webvirtcloud.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
|
||||
|
||||
|
|
@ -85,12 +90,12 @@ DATABASES = {
|
|||
|
||||
AUTHENTICATION_BACKENDS = [
|
||||
'django.contrib.auth.backends.ModelBackend',
|
||||
#'django.contrib.auth.backends.RemoteUserBackend',
|
||||
#'accounts.backends.MyRemoteUserBackend',
|
||||
]
|
||||
|
||||
LOGIN_URL = '/accounts/login'
|
||||
|
||||
LOGOUT_REDIRECT_URL = '/accounts/login'
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
|
@ -154,3 +159,4 @@ LIBVIRT_KEEPALIVE_COUNT = 5
|
|||
ALLOW_EMPTY_PASSWORD = True
|
||||
NEW_USER_DEFAULT_INSTANCES = []
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,14 +7,13 @@ from appsettings.views import appsettings
|
|||
|
||||
urlpatterns = [
|
||||
path('', index, name='index'),
|
||||
|
||||
path('instances/', include('instances.urls')),
|
||||
path('accounts/', include('accounts.urls')),
|
||||
path('computes/', include('computes.urls')),
|
||||
path('logs/', include('logs.urls')),
|
||||
path('datasource/', include('datasource.urls')),
|
||||
path('console/', console, name='console'),
|
||||
path('admin/', include(('admin.urls', 'admin'), namespace='admin')),
|
||||
path('appsettings/', appsettings, name='appsettings'),
|
||||
path('accounts/', include('accounts.urls')),
|
||||
path('computes/', include('computes.urls')),
|
||||
path('console/', console, name='console'),
|
||||
path('datasource/', include('datasource.urls')),
|
||||
path('logs/', include('logs.urls')),
|
||||
path('instances/', include('instances.urls')),
|
||||
path('i18n/', include('django.conf.urls.i18n')),
|
||||
# path('admin/', include(admin.site.urls)),
|
||||
]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue