mirror of
https://github.com/retspen/webvirtcloud
synced 2026-03-22 02:24:56 +00:00
Merge branch 'master' of https://github.com/retspen/webvirtcloud
This commit is contained in:
commit
3125e9d17c
65 changed files with 1126 additions and 1231 deletions
|
|
@ -10,19 +10,19 @@ def apply_change_password(sender, **kwargs):
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User, Permission
|
from django.contrib.auth.models import User, Permission
|
||||||
if hasattr(settings, 'SHOW_PROFILE_EDIT_PASSWORD'):
|
if hasattr(settings, 'SHOW_PROFILE_EDIT_PASSWORD'):
|
||||||
print('\033[92mSHOW_PROFILE_EDIT_PASSWORD is found inside settings.py\033[0m')
|
print('\033[1m! \033[92mSHOW_PROFILE_EDIT_PASSWORD is found inside settings.py\033[0m')
|
||||||
print('\033[92mApplying permission can_change_password for all users\033[0m')
|
print('\033[1m* \033[92mApplying permission can_change_password for all users\033[0m')
|
||||||
users = User.objects.all()
|
users = User.objects.all()
|
||||||
permission = Permission.objects.get(codename='change_password')
|
permission = Permission.objects.get(codename='change_password')
|
||||||
if settings.SHOW_PROFILE_EDIT_PASSWORD:
|
if settings.SHOW_PROFILE_EDIT_PASSWORD:
|
||||||
print('\033[91mWarning!!! Setting to True for all users\033[0m')
|
print('\033[1m! \033[91mWarning!!! Setting to True for all users\033[0m')
|
||||||
for user in users:
|
for user in users:
|
||||||
user.user_permissions.add(permission)
|
user.user_permissions.add(permission)
|
||||||
else:
|
else:
|
||||||
print('\033[91mWarning!!! Setting to False for all users\033[0m')
|
print('\033[1m* \033[91mWarning!!! Setting to False for all users\033[0m')
|
||||||
for user in users:
|
for user in users:
|
||||||
user.user_permissions.remove(permission)
|
user.user_permissions.remove(permission)
|
||||||
print('\033[1mDon`t forget to remove the option from settings.py\033[0m')
|
print('\033[1m! Don`t forget to remove the option from settings.py\033[0m')
|
||||||
|
|
||||||
|
|
||||||
def create_admin(sender, **kwargs):
|
def create_admin(sender, **kwargs):
|
||||||
|
|
@ -32,11 +32,11 @@ def create_admin(sender, **kwargs):
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from accounts.models import UserAttributes
|
from accounts.models import UserAttributes
|
||||||
|
|
||||||
plan = kwargs['plan']
|
plan = kwargs.get('plan', [])
|
||||||
for migration, rolled_back in plan:
|
for migration, rolled_back in plan:
|
||||||
if migration.app_label == 'accounts' and migration.name == '0001_initial' and not rolled_back:
|
if migration.app_label == 'accounts' and migration.name == '0001_initial' and not rolled_back:
|
||||||
if User.objects.count() == 0:
|
if User.objects.count() == 0:
|
||||||
print('\033[92mCreating default admin user\033[0m')
|
print('\033[1m* \033[92mCreating default admin user\033[0m')
|
||||||
admin = User.objects.create_superuser('admin', None, 'admin')
|
admin = User.objects.create_superuser('admin', None, 'admin')
|
||||||
UserAttributes(user=admin, max_instances=-1, max_cpus=-1, max_memory=-1, max_disk_size=-1).save()
|
UserAttributes(user=admin, max_instances=-1, max_cpus=-1, max_memory=-1, max_disk_size=-1).save()
|
||||||
break
|
break
|
||||||
|
|
@ -47,5 +47,5 @@ class AccountsConfig(AppConfig):
|
||||||
verbose_name = 'Accounts'
|
verbose_name = 'Accounts'
|
||||||
|
|
||||||
def ready(self):
|
def ready(self):
|
||||||
post_migrate.connect(apply_change_password, sender=self)
|
|
||||||
post_migrate.connect(create_admin, sender=self)
|
post_migrate.connect(create_admin, sender=self)
|
||||||
|
post_migrate.connect(apply_change_password, sender=self)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
from appsettings.settings import app_settings
|
from appsettings.settings import app_settings
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.forms import ModelForm, ValidationError
|
from django.forms import ModelForm, ValidationError
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from .models import UserInstance, UserSSHKey
|
from .models import UserInstance, UserSSHKey
|
||||||
from .utils import validate_ssh_key
|
from .utils import validate_ssh_key
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.validators import MinValueValidator
|
from django.core.validators import MinValueValidator
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from instances.models import Instance
|
from instances.models import Instance
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,13 @@
|
||||||
{% load qr_code %}
|
{% load qr_code %}
|
||||||
|
|
||||||
{% block title %}{% trans "User Profile" %} - {{ user }}{% endblock %}
|
{% block title %}{% trans "User Profile" %} - {{ user }}{% endblock %}
|
||||||
{% block page_header %}{% trans "User Profile" %}: {{ user }}{% endblock page_header %}
|
{% block page_heading %}{% trans "User Profile" %}: {{ user }}{% endblock page_heading %}
|
||||||
|
|
||||||
{% block page_header_extra %}
|
{% block page_heading_extra %}
|
||||||
<a href="{% url 'accounts:user_instance_create' user.id %}" class="btn btn-success">
|
<a href="{% url 'accounts:user_instance_create' user.id %}" class="btn btn-success">
|
||||||
{% icon 'plus' %}
|
{% icon 'plus' %}
|
||||||
</a>
|
</a>
|
||||||
{% endblock page_header_extra %}
|
{% endblock page_heading_extra %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<ul class="nav nav-tabs">
|
<ul class="nav nav-tabs">
|
||||||
|
|
|
||||||
|
|
@ -1,175 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% load staticfiles %}
|
|
||||||
{% block title %}{% trans "Users" %}{% endblock %}
|
|
||||||
{% block content %}
|
|
||||||
<!-- Page Heading -->
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12">
|
|
||||||
{% include 'create_user_block.html' %}
|
|
||||||
<div class="float-right search">
|
|
||||||
<input id="filter" class="form-control" type="text" placeholder="{% trans 'Search' %}">
|
|
||||||
</div>
|
|
||||||
<h2 class="page-header">{% trans "Users" %}</h1>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- /.row -->
|
|
||||||
|
|
||||||
{% 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>
|
|
||||||
<i class="fa fa-exclamation-triangle"></i> <strong>{% trans "Warning" %}:</strong> {% trans "You don't have any user" %}
|
|
||||||
</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>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody class="searchable">
|
|
||||||
{% for user in users %}
|
|
||||||
<tr class="{% if not user.is_active %}danger{% endif %}">
|
|
||||||
<td>
|
|
||||||
<a href="{% url 'accounts:account' user.id %}"><strong>{{ user.username }}</strong></a>
|
|
||||||
<a data-toggle="modal" href="#editUser{{ user.id }}" class="float-right" title="{% trans "Edit" %}">
|
|
||||||
<span class="fa fa-cog"></span>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{% if user.is_active %}
|
|
||||||
{% trans "Active" %}
|
|
||||||
{% else %}
|
|
||||||
{% trans "Blocked" %}
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
<td>{% if user.is_staff %}<span class="fa fa-check"></span>{% endif %}</td>
|
|
||||||
<td>{% if user.is_superuser %}<span class="fa fa-check"></span>{% endif %}</td>
|
|
||||||
<td>{% if perms.instances.clone_instances %}<span class="fa fa-check"></span>{% endif %}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
{% for user in users %}
|
|
||||||
<!-- Modal Edit -->
|
|
||||||
<div class="modal fade" id="editUser{{ user.id }}" tabindex="-1" role="dialog" aria-labelledby="editUserLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<form method="post" role="form" aria-label="Edit user form">{% csrf_token %}
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">{% trans "Edit user info" %}</h5>
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-4 col-form-label">{% trans "Name" %}</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<input type="hidden" name="user_id" value="{{ user.id }}">
|
|
||||||
<input type="text" name="name" class="form-control" value="{{ user.username }}" disabled>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-4 col-form-label">{% trans "Password" %}</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<input type="password" name="user_pass" class="form-control" value="">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-4 col-form-label">{% trans "Is staff" %}</label>
|
|
||||||
<div class="col-sm-2">
|
|
||||||
<input type="checkbox" name="user_is_staff" {% if user.is_staff %}checked{% endif %}>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-4 col-form-label">{% trans "Is superuser" %}</label>
|
|
||||||
<div class="col-sm-2">
|
|
||||||
<input type="checkbox" name="user_is_superuser" {% if user.is_superuser %}checked{% endif %}>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-4 col-form-label">{% trans "Can clone instances" %}</label>
|
|
||||||
<div class="col-sm-2">
|
|
||||||
<input type="checkbox" name="userattributes_can_clone_instances" {% if user.userattributes.can_clone_instances %}checked{% endif %}>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-4 col-form-label">{% trans "Max instances" %}</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<input type="text" name="userattributes_max_instances" class="form-control" value="{{ user.userattributes.max_instances }}">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-4 col-form-label">{% trans "Max cpus" %}</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<input type="text" name="userattributes_max_cpus" class="form-control" value="{{ user.userattributes.max_cpus }}">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-4 col-form-label">{% trans "Max memory (MB)" %}</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<input type="text" name="userattributes_max_memory" class="form-control" value="{{ user.userattributes.max_memory }}">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-4 col-form-label">{% trans "Max disk size (GB)" %}</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<input type="text" name="userattributes_max_disk_size" class="form-control" value="{{ user.userattributes.max_disk_size }}">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="submit" class="float-left btn btn-danger" name="delete">
|
|
||||||
{% trans "Delete" %}
|
|
||||||
</button>
|
|
||||||
{% if user.is_active %}
|
|
||||||
<button type="submit" class="btn btn-warning mr-auto" name="block">
|
|
||||||
{% trans "Block" %}
|
|
||||||
</button>
|
|
||||||
{% else %}
|
|
||||||
<button type="submit" class="btn btn-success mr-auto" name="unblock">
|
|
||||||
{% trans "Unblock" %}
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">
|
|
||||||
{% trans "Close" %}
|
|
||||||
</button>
|
|
||||||
<button type="submit" class="btn btn-primary" name="edit">
|
|
||||||
{% trans "Edit" %}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div><!-- /.modal-content -->
|
|
||||||
</div><!-- /.modal-dialog -->
|
|
||||||
</div><!-- /.modal -->
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
{% block script %}
|
|
||||||
<script>
|
|
||||||
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));
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
@ -1,151 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
{% load i18n %}
|
|
||||||
{% block title %}{% trans "Users" %}{% endblock %}
|
|
||||||
{% block content %}
|
|
||||||
<!-- Page Heading -->
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12">
|
|
||||||
{% include 'create_user_block.html' %}
|
|
||||||
<h2 class="page-header">{% trans "Users" %}</h2>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- /.row -->
|
|
||||||
|
|
||||||
{% 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>
|
|
||||||
<i class="fa fa-exclamation-triangle"></i> <strong>{% trans "Warning" %}:</strong> {% trans "You don't have any user" %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% else %}
|
|
||||||
{% for user in users %}
|
|
||||||
<div id="{{ user.username }}" class="col-sm-12 col-md-4">
|
|
||||||
{% if user.is_active %}
|
|
||||||
<div class="card border-success shadow">
|
|
||||||
<div class="card-header bg-success">
|
|
||||||
{% else %}
|
|
||||||
<div class="card border-secondary shadow">
|
|
||||||
<div class="card-header bg-secondary">
|
|
||||||
{% endif %}
|
|
||||||
<h5 class="my-0 card-title">
|
|
||||||
<a class="card-link text-light" href="{% url 'accounts:account' user.id %}"><strong>{{ user.username }}</strong></a>
|
|
||||||
<a class="card-link text-light float-right" data-toggle="modal" href="#editUser{{ user.id }}" title="{% trans "Edit" %}">
|
|
||||||
<span class="fa fa-cog"></span>
|
|
||||||
</a>
|
|
||||||
</h5>
|
|
||||||
</div>
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="row row-cols-2">
|
|
||||||
<div class="col">
|
|
||||||
<p class="card-text font-weight-bold">{% trans "Status" %}:</p>
|
|
||||||
</div>
|
|
||||||
<div class="col">
|
|
||||||
{% if user.is_active %}
|
|
||||||
<p>{% trans "Active" %}</p>
|
|
||||||
{% else %}
|
|
||||||
<p>{% trans "Blocked" %}</p>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Modal Edit -->
|
|
||||||
<div class="modal fade" id="editUser{{ user.id }}" tabindex="-1" role="dialog" aria-labelledby="editUserLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">{% trans "Edit user info" %}</h5>
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<form method="post" aria-label="Edit user form">{% csrf_token %}
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-4 col-form-label">{% trans "Name" %}</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<input type="hidden" name="user_id" value="{{ user.id }}">
|
|
||||||
<input type="text" name="name" class="form-control" value="{{ user.username }}" disabled>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-4 col-form-label">{% trans "Password" %}</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<input type="password" name="user_pass" class="form-control" value="">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-4 col-form-label">{% trans "Is staff" %}</label>
|
|
||||||
<div class="form-check form-check-inline col-sm-2 ml-3">
|
|
||||||
<input class="form-check-input position-static" type="checkbox" name="user_is_staff" {% if user.is_staff %}checked{% endif %}>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-4 col-form-label">{% trans "Is superuser" %}</label>
|
|
||||||
<div class="form-check form-check-inline col-sm-2 ml-3">
|
|
||||||
<input class="form-check-input position-static" type="checkbox" name="user_is_superuser" {% if user.is_superuser %}checked{% endif %}>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-4 col-form-label">{% trans "Can clone instances" %}</label>
|
|
||||||
<div class="form-check form-check-inline col-sm-2 ml-3">
|
|
||||||
<input class="form-check-input position-static" type="checkbox" name="userattributes_can_clone_instances" {% if user.userattributes.can_clone_instances %}checked{% endif %}>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-4 col-form-label">{% trans "Max instances" %}</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<input type="text" name="userattributes_max_instances" class="form-control" value="{{ user.userattributes.max_instances}}" required="True" >
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-4 col-form-label">{% trans "Max cpus" %}</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<input type="text" name="userattributes_max_cpus" class="form-control" value="{{ user.userattributes.max_cpus }}" required="True">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-4 col-form-label">{% trans "Max memory (MB)" %}</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<input type="text" name="userattributes_max_memory" class="form-control" value="{{ user.userattributes.max_memory}}" required="True">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-4 col-form-label">{% trans "Max disk size (GB)" %}</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<input type="text" name="userattributes_max_disk_size" class="form-control" value="{{ user.userattributes.max_disk_size }}" required="True">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="submit" class="btn btn-danger" name="delete">
|
|
||||||
{% trans "Delete" %}
|
|
||||||
</button>
|
|
||||||
{% if user.is_active %}
|
|
||||||
<button type="submit" class="btn btn-warning mr-auto" name="block">
|
|
||||||
{% trans "Block" %}
|
|
||||||
</button>
|
|
||||||
{% else %}
|
|
||||||
<button type="submit" class="btn btn-success mr-auto" name="unblock">
|
|
||||||
{% trans "Unblock" %}
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
<button type="submit" class="btn btn-secondary" data-dismiss="modal">
|
|
||||||
{% trans "Close" %}
|
|
||||||
</button>
|
|
||||||
<button type="submit" class="btn btn-primary" name="edit">
|
|
||||||
{% trans "Edit" %}
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div><!-- /.modal-content -->
|
|
||||||
</div><!-- /.modal-dialog -->
|
|
||||||
</div><!-- /.modal -->
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
{% load i18n %}
|
|
||||||
{% if request.user.is_superuser %}
|
|
||||||
<a href="#AddUser" type="button" class="btn btn-success btn-header float-right" data-toggle="modal">
|
|
||||||
<span class="fa fa-plus" aria-hidden="true"></span>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<!-- Modal pool -->
|
|
||||||
<div class="modal fade" id="AddUser" tabindex="-1" role="dialog" aria-labelledby="AddUserLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<form method="post" aria-label="Add user form">{% csrf_token %}
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">{% trans "Add New User" %}</h5>
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-4 col-form-label">{% trans "Name" %}</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<input type="text" class="form-control" name="name" placeholder="{% trans "john" %}" required pattern="[a-z0-9]+">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-4 col-form-label">{% trans "Password" %}</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<input type="password" class="form-control" name="password" placeholder="*******" {% if not allow_empty_password %}required{% endif %}>
|
|
||||||
</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 %}
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
{% block title %}{% trans "Profile" %}: {{ request.user.first_name }} {{ request.user.last_name}}{% endblock %}
|
{% block title %}{% trans "Profile" %}: {{ request.user.first_name }} {{ request.user.last_name}}{% endblock %}
|
||||||
|
|
||||||
{% block page_header %}{% trans "Profile" %}: {{ request.user.first_name }} {{ request.user.last_name}}{% endblock page_header %}
|
{% block page_heading %}{% trans "Profile" %}: {{ request.user.first_name }} {{ request.user.last_name}}{% endblock page_heading %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<ul class="nav nav-tabs">
|
<ul class="nav nav-tabs">
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
defautl_app_config = 'admin.apps.AdminConfig'
|
||||||
|
|
@ -3,7 +3,7 @@ from django.contrib.auth.models import Group, User
|
||||||
from django.contrib.auth.forms import ReadOnlyPasswordHashField
|
from django.contrib.auth.forms import ReadOnlyPasswordHashField
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.utils.text import format_lazy
|
from django.utils.text import format_lazy
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from accounts.models import UserAttributes
|
from accounts.models import UserAttributes
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
{% load icons %}
|
|
||||||
{% 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">
|
|
||||||
{% 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 %}
|
|
||||||
|
|
@ -15,7 +15,6 @@
|
||||||
<h1 class="page-header">{% trans "Groups" %}</h1>
|
<h1 class="page-header">{% trans "Groups" %}</h1>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% include 'errors_block.html' %}
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{% if not groups %}
|
{% if not groups %}
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
|
|
|
||||||
|
|
@ -1,55 +1,48 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load bootstrap4 %}
|
{% load bootstrap4 %}
|
||||||
|
|
||||||
{% block title %}{% trans "Logs" %}{% endblock %}
|
{% block title %}{% trans "Logs" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_heading %}{% trans "Logs" %}{% endblock page_heading %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<!-- Page Heading -->
|
<div class="row">
|
||||||
<div class="row">
|
<div class="col-lg-12">
|
||||||
<div class="col-lg-12">
|
{% if not logs %}
|
||||||
<h2 class="page-header">{% trans "Logs" %}</h2>
|
<div class="col-lg-12">
|
||||||
</div>
|
<div class="alert alert-warning alert-dismissable">
|
||||||
</div>
|
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
|
||||||
<!-- /.row -->
|
<i class="fa fa-exclamation-triangle"></i> <strong>{% trans "Warning" %}:</strong> {% trans "You don't have any Logs" %}
|
||||||
|
|
||||||
{% include 'errors_block.html' %}
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12">
|
|
||||||
{% if not logs %}
|
|
||||||
<div class="col-lg-12">
|
|
||||||
<div class="alert alert-warning alert-dismissable">
|
|
||||||
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
|
|
||||||
<i class="fa fa-exclamation-triangle"></i> <strong>{% trans "Warning" %}:</strong> {% trans "You don't have any Logs" %}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
</div>
|
||||||
{% include "paging.html" %}
|
{% else %}
|
||||||
<div class="table-responsive">
|
<div class="table-responsive">
|
||||||
<table class="table table-bordered table-hover">
|
<table class="table table-hover table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">#</th>
|
||||||
|
<th scope="col">{% trans "Date" %}</th>
|
||||||
|
<th scope="col">{% trans "User" %}</th>
|
||||||
|
<th scope="col">{% trans "Instance" %}</th>
|
||||||
|
<th scope="col">{% trans "Message" %}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for log in logs %}
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">#</th>
|
<td>{{ log.id }}</td>
|
||||||
<th scope="col">{% trans "Date" %}</th>
|
<td style="width:130px;">{{ log.date|date:"M d H:i:s" }}</td>
|
||||||
<th scope="col">{% trans "User" %}</th>
|
<td>{{ log.user }}</td>
|
||||||
<th scope="col">{% trans "Instance" %}</th>
|
<td>{{ log.instance }}</td>
|
||||||
<th scope="col">{% trans "Message" %}</th>
|
<td>{{ log.message }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
{% endfor %}
|
||||||
<tbody>
|
</tbody>
|
||||||
{% for log in logs %}
|
</table>
|
||||||
<tr>
|
</div>
|
||||||
<td>{{ log.id }}</td>
|
{% bootstrap_pagination logs %}
|
||||||
<td style="width:130px;">{{ log.date|date:"M d H:i:s" }}</td>
|
{% endif %}
|
||||||
<td>{{ log.user }}</td>
|
|
||||||
<td>{{ log.instance }}</td>
|
|
||||||
<td>{{ log.message }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{% bootstrap_pagination logs %}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,13 @@
|
||||||
{% load icons %}
|
{% load icons %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block title %}{% trans "User" %}{% endblock %}
|
{% block title %}{{ title }}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_heading %}{{ title }}{% endblock page_heading %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="card col-sm-10 offset-1">
|
||||||
<div class="col-lg-12">
|
<div class="card-body">
|
||||||
<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">
|
<form id="create-update" action="" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% bootstrap_form user_form layout='horizontal' %}
|
{% bootstrap_form user_form layout='horizontal' %}
|
||||||
|
|
|
||||||
|
|
@ -3,20 +3,21 @@
|
||||||
{% load static %}
|
{% load static %}
|
||||||
{% load common_tags %}
|
{% load common_tags %}
|
||||||
{% load icons %}
|
{% load icons %}
|
||||||
{% block title %}{% trans "Users" %}{% endblock %}
|
|
||||||
{% block content %}
|
{% block title %}{{ title }}{% endblock %}
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12">
|
{% block page_heading %}{{ title }}{% endblock page_heading %}
|
||||||
<a href="{% url 'admin:user_create' %}" class="btn btn-success btn-header float-right">
|
|
||||||
{% icon 'plus' %}
|
{% block page_heading_extra %}
|
||||||
</a>
|
<a href="{% url 'admin:user_create' %}" class="btn btn-success btn-header float-right">
|
||||||
<div class="float-right search">
|
{% icon 'plus' %}
|
||||||
<input id="filter" class="form-control" type="text" placeholder="{% trans "Search" %}">
|
</a>
|
||||||
</div>
|
<div class="float-right search">
|
||||||
<h1 class="page-header">{% trans "Users" %}</h1>
|
<input id="filter" class="form-control" type="text" placeholder="{% trans "Search" %}">
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% include 'errors_block.html' %}
|
{% endblock page_heading_extra %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{% if not users %}
|
{% if not users %}
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ from django.contrib.auth.forms import AdminPasswordChangeForm
|
||||||
from django.contrib.auth.models import Group, User
|
from django.contrib.auth.models import Group, User
|
||||||
from django.core.paginator import Paginator
|
from django.core.paginator import Paginator
|
||||||
from django.shortcuts import get_object_or_404, redirect, render
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from accounts.models import UserAttributes, UserInstance, Instance
|
from accounts.models import UserAttributes, UserInstance, Instance
|
||||||
from appsettings.settings import app_settings
|
from appsettings.settings import app_settings
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
# Generated by Django 2.2.12 on 2020-05-23 12:05
|
# Generated by Django 2.2.12 on 2020-05-23 12:05
|
||||||
|
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
def add_default_settings(apps, schema_editor):
|
def add_default_settings(apps, schema_editor):
|
||||||
setting = apps.get_model("appsettings", "AppSettings")
|
setting = apps.get_model("appsettings", "AppSettings")
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
# Generated by Django 2.2.13 on 2020-07-16 06:37
|
# Generated by Django 2.2.13 on 2020-07-16 06:37
|
||||||
|
|
||||||
from django.db import migrations
|
from django.db import migrations
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
def add_default_settings(apps, schema_editor):
|
def add_default_settings(apps, schema_editor):
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class AppSettings(models.Model):
|
class AppSettings(models.Model):
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,80 +1,74 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% block title %}{% trans "Edit Settings" %}{% endblock %}
|
|
||||||
|
{% block title %}{% trans "Edit Settings" %}{% endblock title %}
|
||||||
|
|
||||||
|
{% block page_heading %}{% trans "Edit Settings" %}{% endblock page_heading %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<!-- Page Heading -->
|
<div class="">
|
||||||
<div class="row">
|
<div class="col-lg-12">
|
||||||
<div class="col-lg-12">
|
<h3 class="page-header">{% trans "App Settings" %}</h3>
|
||||||
<h2 class="page-header">{% trans "Edit Settings" %}</h2>
|
<form action="{% url 'set_language' %}" method="post" style="display:inline" aria-label="Edit language.name_local settings form">{% csrf_token %}
|
||||||
|
<div class="form-group row">
|
||||||
|
<input name="next" type="hidden" value="{{ redirect_to }}">
|
||||||
|
<label class="col-sm-3 col-form-label">{% trans "Language" %}</label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<select name="language" class="form-control" onchange="this.form.submit()">
|
||||||
|
{% get_current_language as LANGUAGE_CODE %}
|
||||||
|
{% get_available_languages as LANGUAGES %}
|
||||||
|
{% get_language_info_list for LANGUAGES as languages %}
|
||||||
|
{% for language in languages %}
|
||||||
|
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected{% endif %}>
|
||||||
|
{{ language.name_local }} ({{ language.code }})
|
||||||
|
</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
<!-- /.row -->
|
{% if request.user.is_superuser %}
|
||||||
|
<form method="post" action="" role="form" aria-label="Edit sass directory settings form">{% csrf_token %}
|
||||||
{% include 'errors_block.html' %}
|
<div class="form-group row">
|
||||||
|
<label class="col-sm-3 col-form-label">{% trans sass_dir.name %}</label>
|
||||||
<div class="">
|
<div class="col-sm-6">
|
||||||
<div class="col-lg-12">
|
<input class="form-control" name="{{ sass_dir.key }}" value="{{ sass_dir.value }}" onchange="this.form.submit()" title="{% trans sass_dir.description %}"/>
|
||||||
<h3 class="page-header">{% trans "App Settings" %}</h3>
|
</div>
|
||||||
<form action="{% url 'set_language' %}" method="post" style="display:inline" aria-label="Edit language.name_local settings form">{% csrf_token %}
|
</div>
|
||||||
<div class="form-group row">
|
</form>
|
||||||
<input name="next" type="hidden" value="{{ redirect_to }}">
|
<form method="post" action="" role="form" aria-label="Edit theme settings form">{% csrf_token %}
|
||||||
<label class="col-sm-3 col-form-label">{% trans "Language" %}</label>
|
<div class="form-group row">
|
||||||
<div class="col-sm-6">
|
<label class="col-sm-3 col-form-label">{% trans bootstrap_theme.name %}</label>
|
||||||
<select name="language" class="form-control" onchange="this.form.submit()">
|
<div class="col-sm-6">
|
||||||
{% get_current_language as LANGUAGE_CODE %}
|
<select class="form-control" name="{{ bootstrap_theme.key }}" onchange="this.form.submit()" title="{% trans bootstrap_theme.description %}">
|
||||||
{% get_available_languages as LANGUAGES %}
|
{% for theme in themes_list %}
|
||||||
{% get_language_info_list for LANGUAGES as languages %}
|
<option {% if bootstrap_theme.value == theme %}selected{% endif %} value="{{ theme }}">{{ theme }}</option>
|
||||||
{% for language in languages %}
|
{% endfor %}
|
||||||
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected{% endif %}>
|
</select>
|
||||||
{{ language.name_local }} ({{ language.code }})
|
<span class="text-muted">{% trans "After change please full refresh page with 'Ctrl + F5' "%}</span>
|
||||||
</option>
|
</div>
|
||||||
{% endfor %}
|
</div>
|
||||||
</select>
|
</form>
|
||||||
</div>
|
{% endif %}
|
||||||
</div>
|
<h3 class="page-header">{% trans "Other Settings" %}</h3>
|
||||||
</form>
|
{% for setting in appsettings %}
|
||||||
{% if request.user.is_superuser %}
|
<form method="post" action="" role="form" aria-label="{{setting.name}} form">{% csrf_token %}
|
||||||
<form method="post" action="" role="form" aria-label="Edit sass directory settings form">{% csrf_token %}
|
<div class="form-group row">
|
||||||
<div class="form-group row">
|
<label class="col-sm-3 col-form-label">{% trans setting.name %}</label>
|
||||||
<label class="col-sm-3 col-form-label">{% trans sass_dir.name %}</label>
|
<div class="col-sm-6">
|
||||||
<div class="col-sm-6">
|
{% if setting.choices %}
|
||||||
<input class="form-control" name="{{ sass_dir.key }}" value="{{ sass_dir.value }}" onchange="this.form.submit()" title="{% trans sass_dir.description %}"/>
|
<select class="form-control" name="{{ setting.key }}" onchange="this.form.submit()" title="{% trans setting.description %}">
|
||||||
</div>
|
{% for choice in setting.choices_as_list %}
|
||||||
</div>
|
<option {% if setting.value == choice %} selected {% endif %} value={{ choice }}>{% trans choice %}</option>
|
||||||
</form>
|
|
||||||
<form method="post" action="" role="form" aria-label="Edit theme settings form">{% csrf_token %}
|
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-3 col-form-label">{% trans bootstrap_theme.name %}</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<select class="form-control" name="{{ bootstrap_theme.key }}" onchange="this.form.submit()" title="{% trans bootstrap_theme.description %}">
|
|
||||||
{% for theme in themes_list %}
|
|
||||||
<option {% if bootstrap_theme.value == theme %}selected{% endif %} value="{{ theme }}">{{ theme }}</option>
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<span class="text-muted">{% trans "After change please full refresh page with 'Ctrl + F5' "%}</span>
|
{% else %}
|
||||||
</div>
|
<input class="form-control" name="{{ setting.key }}" value="{{ setting.value }}" title="{% trans setting.description %}" onchange="this.form.submit()"/>
|
||||||
|
{% endif%}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</div>
|
||||||
{% endif %}
|
</form>
|
||||||
<h3 class="page-header">{% trans "Other Settings" %}</h3>
|
{% endfor %}
|
||||||
{% for setting in appsettings %}
|
</div>
|
||||||
<form method="post" action="" role="form" aria-label="{{setting.name}} form">{% csrf_token %}
|
</div>
|
||||||
<div class="form-group row">
|
|
||||||
<label class="col-sm-3 col-form-label">{% trans setting.name %}</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
{% if setting.choices %}
|
|
||||||
<select class="form-control" name="{{ setting.key }}" onchange="this.form.submit()" title="{% trans setting.description %}">
|
|
||||||
{% for choice in setting.choices_as_list %}
|
|
||||||
<option {% if setting.value == choice %} selected {% endif %} value={{ choice }}>{% trans choice %}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
{% else %}
|
|
||||||
<input class="form-control" name="{{ setting.key }}" value="{{ setting.value }}" title="{% trans setting.description %}" onchange="this.form.submit()"/>
|
|
||||||
{% endif%}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,14 @@
|
||||||
import sass
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from django.shortcuts import render
|
import sass
|
||||||
from django.http import HttpResponseRedirect
|
|
||||||
from django.urls import reverse
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
from appsettings.models import AppSettings
|
from django.http import HttpResponseRedirect
|
||||||
|
from django.shortcuts import render
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
from logs.views import addlogmsg
|
from logs.views import addlogmsg
|
||||||
|
|
||||||
|
from appsettings.models import AppSettings
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
|
@ -19,20 +17,18 @@ def appsettings(request):
|
||||||
:param request:
|
:param request:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
error_messages = []
|
|
||||||
main_css = "wvc-main.min.css"
|
main_css = "wvc-main.min.css"
|
||||||
sass_dir = AppSettings.objects.get(key="SASS_DIR")
|
sass_dir = AppSettings.objects.get(key="SASS_DIR")
|
||||||
bootstrap_theme = AppSettings.objects.get(key="BOOTSTRAP_THEME")
|
bootstrap_theme = AppSettings.objects.get(key="BOOTSTRAP_THEME")
|
||||||
try:
|
try:
|
||||||
themes_list = os.listdir(sass_dir.value + "/wvc-theme")
|
themes_list = os.listdir(sass_dir.value + "/wvc-theme")
|
||||||
except FileNotFoundError as err:
|
except FileNotFoundError as err:
|
||||||
error_messages.append(err)
|
messages.error(request, err)
|
||||||
addlogmsg(request.user.username, "", err)
|
addlogmsg(request.user.username, "", err)
|
||||||
|
|
||||||
# Bootstrap settings related with filesystems, because of that they are excluded from other settings
|
# Bootstrap settings related with filesystems, because of that they are excluded from other settings
|
||||||
appsettings = AppSettings.objects.exclude(description__startswith="Bootstrap").order_by("name")
|
appsettings = AppSettings.objects.exclude(description__startswith="Bootstrap").order_by("name")
|
||||||
|
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
if 'SASS_DIR' in request.POST:
|
if 'SASS_DIR' in request.POST:
|
||||||
try:
|
try:
|
||||||
|
|
@ -43,7 +39,7 @@ def appsettings(request):
|
||||||
messages.success(request, msg)
|
messages.success(request, msg)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
msg = err
|
msg = err
|
||||||
error_messages.append(msg)
|
messages.error(request, msg)
|
||||||
|
|
||||||
addlogmsg(request.user.username, "", msg)
|
addlogmsg(request.user.username, "", msg)
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
|
|
@ -58,7 +54,8 @@ def appsettings(request):
|
||||||
with open(sass_dir.value + "/wvc-main.scss", "w") as main:
|
with open(sass_dir.value + "/wvc-main.scss", "w") as main:
|
||||||
main.write(scss_var + "\n" + scss_boot + "\n" + scss_bootswatch + "\n")
|
main.write(scss_var + "\n" + scss_boot + "\n" + scss_bootswatch + "\n")
|
||||||
|
|
||||||
css_compressed = sass.compile(string=scss_var + "\n"+ scss_boot + "\n" + scss_bootswatch, output_style='compressed')
|
css_compressed = sass.compile(string=scss_var + "\n" + scss_boot + "\n" + scss_bootswatch,
|
||||||
|
output_style='compressed')
|
||||||
with open("static/css/" + main_css, "w") as css:
|
with open("static/css/" + main_css, "w") as css:
|
||||||
css.write(css_compressed)
|
css.write(css_compressed)
|
||||||
|
|
||||||
|
|
@ -69,7 +66,7 @@ def appsettings(request):
|
||||||
messages.success(request, msg)
|
messages.success(request, msg)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
msg = err
|
msg = err
|
||||||
error_messages.append(msg)
|
messages.error(request, msg)
|
||||||
|
|
||||||
addlogmsg(request.user.username, "", msg)
|
addlogmsg(request.user.username, "", msg)
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
|
|
@ -84,10 +81,9 @@ def appsettings(request):
|
||||||
messages.success(request, msg)
|
messages.success(request, msg)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
msg = err
|
msg = err
|
||||||
error_messages.append(msg)
|
messages.error(request, msg)
|
||||||
|
|
||||||
addlogmsg(request.user.username, "", msg)
|
addlogmsg(request.user.username, "", msg)
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
|
|
||||||
return render(request, 'appsettings.html', locals())
|
return render(request, 'appsettings.html', locals())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import re
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from vrtManager.connection import CONN_SOCKET, CONN_SSH, CONN_TCP, CONN_TLS
|
||||||
|
|
||||||
from computes.models import Compute
|
from computes.models import Compute
|
||||||
from vrtManager.connection import CONN_TCP, CONN_SSH, CONN_TLS, CONN_SOCKET
|
|
||||||
from .validators import validate_hostname
|
from .validators import validate_hostname
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from django.db.models import CharField, IntegerField, Model
|
from django.db.models import CharField, IntegerField, Model
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from libvirt import virConnect
|
from libvirt import virConnect
|
||||||
|
|
||||||
from vrtManager.connection import connection_manager
|
from vrtManager.connection import connection_manager
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@
|
||||||
{% block style %}
|
{% block style %}
|
||||||
<link rel="stylesheet" href="{% static "css/sortable-theme-bootstrap.css" %}" />
|
<link rel="stylesheet" href="{% static "css/sortable-theme-bootstrap.css" %}" />
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block page_header %}{{ compute.name }}{% endblock page_header %}
|
{% block page_heading %}{{ compute.name }}{% endblock page_heading %}
|
||||||
|
|
||||||
{% block page_header_extra %}
|
{% block page_heading_extra %}
|
||||||
<a href="{% url 'instances:create_instance_select_type' compute.id %}"
|
<a href="{% url 'instances:create_instance_select_type' compute.id %}"
|
||||||
class="btn btn-success btn-header float-right">
|
class="btn btn-success btn-header float-right">
|
||||||
{% icon 'plus' %}
|
{% icon 'plus' %}
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
<input id="filter" class="form-control" type="text" placeholder="{% trans 'Search' %}">
|
<input id="filter" class="form-control" type="text" placeholder="{% trans 'Search' %}">
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock page_header_extra %}
|
{% endblock page_heading_extra %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@
|
||||||
<h3 class="page-header">{% trans "Computes" %}</h3>
|
<h3 class="page-header">{% trans "Computes" %}</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% include 'errors_block.html' %}
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{% if not computes %}
|
{% if not computes %}
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
|
|
|
||||||
|
|
@ -1,42 +1,42 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
|
{% load icons %}
|
||||||
|
|
||||||
{% block title %}{% trans "Overview" %} - {{ compute.name }}{% endblock %}
|
{% block title %}{% trans "Overview" %} - {{ compute.name }}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_heading %}{{ compute.name }}{% endblock page_heading %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<!-- Page Heading -->
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<h2 class="page-header">{{ compute.name }}</h2>
|
|
||||||
<nav aria-label="breadcrumb">
|
<nav aria-label="breadcrumb">
|
||||||
<ol class="breadcrumb bg-light shadow-sm">
|
<ol class="breadcrumb bg-light shadow-sm">
|
||||||
<li class="breadcrumb-item active">
|
<li class="breadcrumb-item">
|
||||||
<span class="font-weight-bold"><i class="fa fa-dashboard"></i> {% trans "Overview" %}</span>
|
<span class="font-weight-bold">{% icon 'dashboard' %} {% trans "Overview" %}</span>
|
||||||
</li>
|
</li>
|
||||||
<li class="breadcrumb-item">
|
<li class="breadcrumb-item">
|
||||||
<a href="{% url 'instances' compute.id %}"><i class="fa fa-server"></i> {% trans "Instances" %}</a>
|
<a href="{% url 'instances' compute.id %}">{% icon 'server' %} {% trans "Instances" %}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="breadcrumb-item">
|
<li class="breadcrumb-item">
|
||||||
<a href="{% url 'storages' compute.id %}"><i class="fa fa-hdd-o"></i> {% trans "Storages" %}</a>
|
<a href="{% url 'storages' compute.id %}">{% icon 'hdd-o' %} {% trans "Storages" %}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="breadcrumb-item">
|
<li class="breadcrumb-item">
|
||||||
<a href="{% url 'networks' compute.id %}"><i class="fa fa-sitemap"></i> {% trans "Networks" %}</a>
|
<a href="{% url 'networks' compute.id %}">{% icon 'sitemap' %} {% trans "Networks" %}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="breadcrumb-item">
|
<li class="breadcrumb-item">
|
||||||
<a href="{% url 'interfaces' compute.id %}"><i class="fa fa-wifi"></i> {% trans "Interfaces" %}</a>
|
<a href="{% url 'interfaces' compute.id %}">{% icon 'wifi' %} {% trans "Interfaces" %}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="breadcrumb-item">
|
<li class="breadcrumb-item">
|
||||||
<a href="{% url 'nwfilters' compute.id %}"><i class="fa fa-filter"></i> {% trans "NWFilters" %}</a>
|
<a href="{% url 'nwfilters' compute.id %}">{% icon 'filter' %} {% trans "NWFilters" %}</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="breadcrumb-item">
|
<li class="breadcrumb-item">
|
||||||
<a href="{% url 'secrets' compute.id %}"><i class="fa fa-key"></i> {% trans "Secrets" %}</a>
|
<a href="{% url 'secrets' compute.id %}">{% icon 'key' %} {% trans "Secrets" %}</a>
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.row -->
|
|
||||||
|
|
||||||
{% include 'errors_block.html' %}
|
|
||||||
|
|
||||||
<div class="shadow-sm">
|
<div class="shadow-sm">
|
||||||
<h3 class="page-header">{% trans "Basic details" %}</h3>
|
<h3 class="page-header">{% trans "Basic details" %}</h3>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
import re
|
import re
|
||||||
|
|
||||||
have_symbol = re.compile('[^a-zA-Z0-9._-]+')
|
have_symbol = re.compile('[^a-zA-Z0-9._-]+')
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
<domain type="kvm">
|
<domain type="kvm">
|
||||||
<name>test-vm</name>
|
<name>test-vm</name>
|
||||||
<uuid>1bd3c1f2-dd12-4b8d-a298-dff387cb9f93</uuid>
|
<uuid>1bd3c1f2-dd12-4b8d-a298-dff387cb9f93</uuid>
|
||||||
<description>None</description>
|
|
||||||
<memory unit="KiB">131072</memory>
|
<memory unit="KiB">131072</memory>
|
||||||
<currentMemory unit="KiB">131072</currentMemory>
|
<currentMemory unit="KiB">131072</currentMemory>
|
||||||
<vcpu placement="static">1</vcpu>
|
<vcpu placement="static">1</vcpu>
|
||||||
|
|
|
||||||
|
|
@ -6,38 +6,41 @@ def migrate_can_clone_instances(sender, **kwargs):
|
||||||
'''
|
'''
|
||||||
Migrate can clone instances user attribute to permission
|
Migrate can clone instances user attribute to permission
|
||||||
'''
|
'''
|
||||||
from django.conf import settings
|
from django.contrib.auth.models import Permission, User
|
||||||
from django.contrib.auth.models import User, Permission
|
|
||||||
from accounts.models import UserAttributes
|
|
||||||
|
|
||||||
plan = kwargs['plan']
|
plan = kwargs.get('plan', [])
|
||||||
for migration, rolled_back in plan:
|
for migration, rolled_back in plan:
|
||||||
if migration.app_label == 'instances' and migration.name == '0002_permissionset' and not rolled_back:
|
if migration.app_label == 'instances' and migration.name == '0002_permissionset' and not rolled_back:
|
||||||
users = User.objects.all()
|
users = User.objects.all()
|
||||||
permission = Permission.objects.get(codename='clone_instances')
|
permission = Permission.objects.get(codename='clone_instances')
|
||||||
print('\033[92mMigrating can_clone_instaces user attribute to permission\033[0m')
|
print('\033[1m* \033[92mMigrating can_clone_instaces user attribute to permission\033[0m')
|
||||||
for user in users:
|
for user in users:
|
||||||
if user.userattributes:
|
if user.userattributes:
|
||||||
if user.userattributes.can_clone_instances:
|
if user.userattributes.can_clone_instances:
|
||||||
user.user_permissions.add(permission)
|
user.user_permissions.add(permission)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
def apply_passwordless_console(sender, **kwargs):
|
def apply_passwordless_console(sender, **kwargs):
|
||||||
'''
|
'''
|
||||||
Apply new passwordless_console permission for all users
|
Apply new passwordless_console permission for all users
|
||||||
'''
|
'''
|
||||||
from django.conf import settings
|
from django.contrib.auth.models import Permission
|
||||||
from django.contrib.auth.models import User, Permission
|
from django.contrib.auth import get_user_model
|
||||||
|
User = get_user_model()
|
||||||
|
plan = kwargs.get('plan', [])
|
||||||
|
for migration, rolled_back in plan:
|
||||||
|
if migration.app_label == 'instances' and migration.name == '0009_auto_20200717_0524' and not rolled_back:
|
||||||
|
print('\033[1m* \033[92mApplying permission passwordless_console for all users\033[0m')
|
||||||
|
users = User.objects.all()
|
||||||
|
permission = Permission.objects.get(codename='passwordless_console')
|
||||||
|
for user in users:
|
||||||
|
user.user_permissions.add(permission)
|
||||||
|
|
||||||
print('\033[92mApplying permission passwordless_console for all users\033[0m')
|
|
||||||
users = User.objects.all()
|
|
||||||
permission = Permission.objects.get(codename='passwordless_console')
|
|
||||||
for user in users:
|
|
||||||
user.user_permissions.add(permission)
|
|
||||||
|
|
||||||
class InstancesConfig(AppConfig):
|
class InstancesConfig(AppConfig):
|
||||||
name = 'instances'
|
name = 'instances'
|
||||||
verbose_name = 'instances'
|
verbose_name = 'Instances'
|
||||||
|
|
||||||
def ready(self):
|
def ready(self):
|
||||||
post_migrate.connect(migrate_can_clone_instances, sender=self)
|
post_migrate.connect(migrate_can_clone_instances, sender=self)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from appsettings.models import AppSettings
|
from appsettings.models import AppSettings
|
||||||
from webvirtcloud.settings import QEMU_CONSOLE_LISTEN_ADDRESSES, QEMU_KEYMAPS
|
from webvirtcloud.settings import QEMU_CONSOLE_LISTEN_ADDRESSES, QEMU_KEYMAPS
|
||||||
|
|
@ -61,6 +61,4 @@ class NewVMForm(forms.Form):
|
||||||
have_symbol = re.match('^[a-zA-Z0-9._-]+$', name)
|
have_symbol = re.match('^[a-zA-Z0-9._-]+$', name)
|
||||||
if not have_symbol:
|
if not have_symbol:
|
||||||
raise forms.ValidationError(_('The name of the virtual machine must not contain any special characters'))
|
raise forms.ValidationError(_('The name of the virtual machine must not contain any special characters'))
|
||||||
elif len(name) > 64:
|
|
||||||
raise forms.ValidationError(_('The name of the virtual machine must not exceed 20 characters'))
|
|
||||||
return name
|
return name
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from libvirt import VIR_DOMAIN_XML_SECURE
|
from libvirt import VIR_DOMAIN_XML_SECURE
|
||||||
|
|
||||||
from computes.models import Compute
|
from computes.models import Compute
|
||||||
|
|
|
||||||
|
|
@ -6,16 +6,16 @@
|
||||||
{% block style %}
|
{% block style %}
|
||||||
<link rel="stylesheet" href="{% static "css/sortable-theme-bootstrap.css" %}" />
|
<link rel="stylesheet" href="{% static "css/sortable-theme-bootstrap.css" %}" />
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block page_header %}{% trans "Instances" %}{% endblock page_header %}
|
{% block page_heading %}{% trans "Instances" %}{% endblock page_heading %}
|
||||||
|
|
||||||
{% block page_header_extra %}
|
{% block page_heading_extra %}
|
||||||
{% if request.user.is_superuser %}
|
{% if request.user.is_superuser %}
|
||||||
{% include 'create_inst_block.html' %}
|
{% include 'create_inst_block.html' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="float-right search">
|
<div class="float-right search">
|
||||||
<input id="filter" class="form-control" type="text" placeholder="{% trans 'Search' %}">
|
<input id="filter" class="form-control" type="text" placeholder="{% trans 'Search' %}">
|
||||||
</div>
|
</div>
|
||||||
{% endblock page_header_extra %}
|
{% endblock page_heading_extra %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% for compute in computes %}
|
{% for compute in computes %}
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,15 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
|
|
||||||
{% block title %}{% trans "Create new instance" %} - {% trans "Select Type" %}{% endblock %}
|
{% block title %}{% trans "Create new instance" %} - {% trans "Select Type" %}{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block page_heading%}
|
||||||
<!-- Page Heading -->
|
{% blocktrans with host=compute.name %}New instance on {{ host }} {% endblocktrans %}
|
||||||
<div class="row">
|
{% endblock page_heading %}
|
||||||
<div class="col-lg-12">
|
|
||||||
<h3 class="page-header">
|
|
||||||
{% blocktrans with host=compute.name %}New instance on {{ host }} {% endblocktrans %}
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- /.row -->
|
|
||||||
{% include 'errors_block.html' %}
|
|
||||||
{% include 'pleasewaitdialog.html' %}
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% include 'pleasewaitdialog.html' %}
|
||||||
|
|
||||||
{% if form.errors %}
|
{% if form.errors %}
|
||||||
{% for field in form %}
|
{% for field in form %}
|
||||||
|
|
|
||||||
|
|
@ -3,22 +3,17 @@
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
{% load icons %}
|
{% load icons %}
|
||||||
{% block title %}{% trans "Create new instance" %}{% endblock %}
|
{% block title %}{% trans "Create new instance" %}{% endblock %}
|
||||||
|
|
||||||
{% block style %}
|
{% block style %}
|
||||||
<link href="{% static "css/bootstrap-multiselect.css" %}" rel="stylesheet">
|
<link href="{% static "css/bootstrap-multiselect.css" %}" rel="stylesheet">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
|
||||||
<!-- Page Heading -->
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12">
|
|
||||||
<h3 class="page-header">
|
|
||||||
{% blocktrans with host=compute.name %}New instance on {{ host }} {% endblocktrans %}</h3>
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- /.row -->
|
|
||||||
{% include 'errors_block.html' %}
|
|
||||||
{% include 'pleasewaitdialog.html' %}
|
|
||||||
|
|
||||||
|
{% block page_heading %}
|
||||||
|
{% blocktrans with host=compute.name %}New instance on {{ host }} {% endblocktrans %}
|
||||||
|
{% endblock page_heading %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
{% include 'pleasewaitdialog.html' %}
|
||||||
|
|
||||||
{% if form.errors %}
|
{% if form.errors %}
|
||||||
{% for field in form %}
|
{% for field in form %}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,16 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block title %}{% trans "Instance" %} - {{ instance.name }}{% endblock %}
|
{% block title %}{% trans "Instance" %} - {{ instance.name }}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_heading %}
|
||||||
|
{{ instance.name }}{% if instance.title %} ({{ instance.title }}){% endif %}
|
||||||
|
{% endblock page_heading %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% include 'pleasewaitdialog.html' %}
|
{% include 'pleasewaitdialog.html' %}
|
||||||
<!-- Page Heading -->
|
|
||||||
<div>
|
<div>
|
||||||
<div>
|
|
||||||
<h3>{{ instance.name }}{% if instance.title %} ({{ instance.title }}){% endif %}</h3>
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
{% if instance.status == 5 %}
|
{% if instance.status == 5 %}
|
||||||
<span class="badge badge-danger">{% trans "Off" %}</span>
|
<span class="badge badge-danger">{% trans "Off" %}</span>
|
||||||
|
|
@ -62,8 +64,6 @@
|
||||||
<hr>
|
<hr>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% include 'errors_block.html' %}
|
|
||||||
|
|
||||||
<div class="row" id="max-width-page">
|
<div class="row" id="max-width-page">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div role="tabpanel">
|
<div role="tabpanel">
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,9 @@
|
||||||
{% trans "Confirm Destroy" %}
|
{% trans "Confirm Destroy" %}
|
||||||
{% endblock title %}
|
{% endblock title %}
|
||||||
|
|
||||||
{% block page_header %}
|
{% block page_heading %}
|
||||||
{% trans "Destroy instance" %} {{ instance }}
|
{% trans "Destroy instance" %} {{ instance }}
|
||||||
{% endblock page_header %}
|
{% endblock page_heading %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% if request.user.is_superuser or userinstance.is_delete %}
|
{% if request.user.is_superuser or userinstance.is_delete %}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -65,5 +65,5 @@ urlpatterns = [
|
||||||
path('guess_clone_name/', views.guess_clone_name, name='guess_clone_name'),
|
path('guess_clone_name/', views.guess_clone_name, name='guess_clone_name'),
|
||||||
path('random_mac_address/', views.random_mac_address, name='random_mac_address'),
|
path('random_mac_address/', views.random_mac_address, name='random_mac_address'),
|
||||||
path('check_instance/<vname>/', views.check_instance, name='check_instance'),
|
path('check_instance/<vname>/', views.check_instance, name='check_instance'),
|
||||||
path('sshkeys/<vname>/', views.sshkeys, name='sshkeys'),
|
path('<int:pk>/sshkeys/', views.sshkeys, name='sshkeys'),
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,40 +1,17 @@
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import string
|
import string
|
||||||
from collections import OrderedDict
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.contrib.auth.models import User
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
|
||||||
|
|
||||||
from accounts.models import UserInstance
|
from accounts.models import UserInstance
|
||||||
from appsettings.settings import app_settings
|
from appsettings.settings import app_settings
|
||||||
from logs.views import addlogmsg
|
from django.conf import settings
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
from vrtManager.connection import connection_manager
|
from vrtManager.connection import connection_manager
|
||||||
from vrtManager.hostdetails import wvmHostDetails
|
|
||||||
from vrtManager.instance import wvmInstance, wvmInstances
|
from vrtManager.instance import wvmInstance, wvmInstances
|
||||||
|
|
||||||
from .models import Instance
|
from .models import Instance
|
||||||
|
|
||||||
|
|
||||||
def filesizefstr(size_str):
|
|
||||||
if size_str == '':
|
|
||||||
return 0
|
|
||||||
size_str = size_str.upper().replace("B", "")
|
|
||||||
if size_str[-1] == 'K':
|
|
||||||
return int(float(size_str[:-1])) << 10
|
|
||||||
elif size_str[-1] == 'M':
|
|
||||||
return int(float(size_str[:-1])) << 20
|
|
||||||
elif size_str[-1] == 'G':
|
|
||||||
return int(float(size_str[:-1])) << 30
|
|
||||||
elif size_str[-1] == 'T':
|
|
||||||
return int(float(size_str[:-1])) << 40
|
|
||||||
elif size_str[-1] == 'P':
|
|
||||||
return int(float(size_str[:-1])) << 50
|
|
||||||
else:
|
|
||||||
return int(float(size_str))
|
|
||||||
|
|
||||||
|
|
||||||
def get_clone_free_names(size=10):
|
def get_clone_free_names(size=10):
|
||||||
prefix = app_settings.CLONE_INSTANCE_DEFAULT_PREFIX
|
prefix = app_settings.CLONE_INSTANCE_DEFAULT_PREFIX
|
||||||
free_names = []
|
free_names = []
|
||||||
|
|
@ -186,36 +163,6 @@ def migrate_instance(
|
||||||
instance.save()
|
instance.save()
|
||||||
|
|
||||||
|
|
||||||
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,
|
|
||||||
})
|
|
||||||
return compute_data
|
|
||||||
|
|
||||||
|
|
||||||
def get_userinstances_info(instance):
|
|
||||||
info = {}
|
|
||||||
uis = UserInstance.objects.filter(instance=instance)
|
|
||||||
info['count'] = uis.count()
|
|
||||||
if info['count'] > 0:
|
|
||||||
info['first_user'] = uis[0]
|
|
||||||
else:
|
|
||||||
info['first_user'] = None
|
|
||||||
return info
|
|
||||||
|
|
||||||
|
|
||||||
def refr(compute):
|
def refr(compute):
|
||||||
if compute.status is True:
|
if compute.status is True:
|
||||||
domains = compute.proxy.wvm.listAllDomains()
|
domains = compute.proxy.wvm.listAllDomains()
|
||||||
|
|
@ -229,83 +176,6 @@ def refr(compute):
|
||||||
Instance(compute=compute, name=domain.name(), uuid=domain.UUIDString()).save()
|
Instance(compute=compute, name=domain.name(), uuid=domain.UUIDString()).save()
|
||||||
|
|
||||||
|
|
||||||
def refresh_instance_database(comp, inst_name, info, all_host_vms, user):
|
|
||||||
# Multiple Instance Name Check
|
|
||||||
instances = Instance.objects.filter(name=inst_name)
|
|
||||||
if instances.count() > 1:
|
|
||||||
for i in instances:
|
|
||||||
user_instances_count = UserInstance.objects.filter(instance=i).count()
|
|
||||||
if user_instances_count == 0:
|
|
||||||
addlogmsg(user.username, i.name, _("Deleting due to multiple(Instance Name) records."))
|
|
||||||
i.delete()
|
|
||||||
|
|
||||||
# Multiple UUID Check
|
|
||||||
instances = Instance.objects.filter(uuid=info['uuid'])
|
|
||||||
if instances.count() > 1:
|
|
||||||
for i in instances:
|
|
||||||
if i.name != inst_name:
|
|
||||||
addlogmsg(user.username, i.name, _("Deleting due to multiple(UUID) records."))
|
|
||||||
i.delete()
|
|
||||||
|
|
||||||
try:
|
|
||||||
inst_on_db = Instance.objects.get(compute_id=comp["id"], name=inst_name)
|
|
||||||
if inst_on_db.uuid != info['uuid']:
|
|
||||||
inst_on_db.save()
|
|
||||||
|
|
||||||
all_host_vms[comp["id"], comp["name"], comp["status"], comp["cpu"], comp["mem_size"],
|
|
||||||
comp["mem_perc"]][inst_name]['is_template'] = inst_on_db.is_template
|
|
||||||
all_host_vms[comp["id"], comp["name"], comp["status"], comp["cpu"], comp["mem_size"],
|
|
||||||
comp["mem_perc"]][inst_name]['userinstances'] = get_userinstances_info(inst_on_db)
|
|
||||||
except Instance.DoesNotExist:
|
|
||||||
inst_on_db = Instance(compute_id=comp["id"], name=inst_name, uuid=info['uuid'])
|
|
||||||
inst_on_db.save()
|
|
||||||
|
|
||||||
|
|
||||||
def get_user_instances(user):
|
|
||||||
all_user_vms = {}
|
|
||||||
user_instances = UserInstance.objects.filter(user=user)
|
|
||||||
for usr_inst in user_instances:
|
|
||||||
if connection_manager.host_is_up(usr_inst.instance.compute.type, usr_inst.instance.compute.hostname):
|
|
||||||
conn = wvmHostDetails(
|
|
||||||
usr_inst.instance.compute.hostname,
|
|
||||||
usr_inst.instance.compute.login,
|
|
||||||
usr_inst.instance.compute.password,
|
|
||||||
usr_inst.instance.compute.type,
|
|
||||||
)
|
|
||||||
all_user_vms[usr_inst] = conn.get_user_instances(usr_inst.instance.name)
|
|
||||||
all_user_vms[usr_inst].update({'compute_id': usr_inst.instance.compute.id})
|
|
||||||
return all_user_vms
|
|
||||||
|
|
||||||
|
|
||||||
def get_host_instances(compute):
|
|
||||||
all_host_vms = OrderedDict()
|
|
||||||
|
|
||||||
# if compute.status:
|
|
||||||
comp_node_info = compute.proxy.get_node_info()
|
|
||||||
comp_mem = compute.proxy.get_memory_usage()
|
|
||||||
comp_instances = compute.proxy.get_host_instances(True)
|
|
||||||
|
|
||||||
# if comp_instances:
|
|
||||||
comp_info = {
|
|
||||||
"id": compute.id,
|
|
||||||
"name": compute.name,
|
|
||||||
"status": compute.status,
|
|
||||||
"cpu": comp_node_info[3],
|
|
||||||
"mem_size": comp_node_info[2],
|
|
||||||
"mem_perc": comp_mem['percent'],
|
|
||||||
}
|
|
||||||
# refr(compute)
|
|
||||||
all_host_vms[comp_info["id"], comp_info["name"], comp_info["status"], comp_info["cpu"], comp_info["mem_size"],
|
|
||||||
comp_info["mem_perc"]] = comp_instances
|
|
||||||
for vm, info in comp_instances.items():
|
|
||||||
# TODO: Delete this function completely
|
|
||||||
refresh_instance_database(comp_info, vm, info, all_host_vms, User.objects.get(pk=1))
|
|
||||||
|
|
||||||
# else:
|
|
||||||
# raise libvirtError(_(f"Problem occurred with host: {compute.name} - {status}"))
|
|
||||||
return all_host_vms
|
|
||||||
|
|
||||||
|
|
||||||
def get_dhcp_mac_address(vname):
|
def get_dhcp_mac_address(vname):
|
||||||
dhcp_file = settings.BASE_DIR + '/dhcpd.conf'
|
dhcp_file = settings.BASE_DIR + '/dhcpd.conf'
|
||||||
mac = ''
|
mac = ''
|
||||||
|
|
@ -342,20 +212,3 @@ def get_clone_disk_name(disk, prefix, clone_name=''):
|
||||||
else:
|
else:
|
||||||
image = f"{disk['image']}-clone"
|
image = f"{disk['image']}-clone"
|
||||||
return image
|
return image
|
||||||
|
|
||||||
|
|
||||||
# TODO: this function is not used
|
|
||||||
def _get_clone_disks(disks, vname=''):
|
|
||||||
clone_disks = []
|
|
||||||
for disk in disks:
|
|
||||||
new_image = get_clone_disk_name(disk, vname)
|
|
||||||
if not new_image:
|
|
||||||
continue
|
|
||||||
new_disk = {
|
|
||||||
'dev': disk['dev'],
|
|
||||||
'storage': disk['storage'],
|
|
||||||
'image': new_image,
|
|
||||||
'format': disk['format'],
|
|
||||||
}
|
|
||||||
clone_disks.append(new_disk)
|
|
||||||
return clone_disks
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ from django.contrib.auth.models import User
|
||||||
from django.http import Http404, HttpResponse, JsonResponse
|
from django.http import Http404, HttpResponse, JsonResponse
|
||||||
from django.shortcuts import get_object_or_404, redirect, render
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from libvirt import (VIR_DOMAIN_UNDEFINE_KEEP_NVRAM, VIR_DOMAIN_UNDEFINE_NVRAM, libvirtError)
|
from libvirt import (VIR_DOMAIN_UNDEFINE_KEEP_NVRAM, VIR_DOMAIN_UNDEFINE_NVRAM, libvirtError)
|
||||||
from logs.views import addlogmsg
|
from logs.views import addlogmsg
|
||||||
from vrtManager import util
|
from vrtManager import util
|
||||||
|
|
@ -51,7 +51,7 @@ def index(request):
|
||||||
|
|
||||||
|
|
||||||
def instance(request, pk):
|
def instance(request, pk):
|
||||||
instance: Instance = get_object_or_404(Instance, pk=pk)
|
instance: Instance = get_instance(request.user, pk)
|
||||||
compute: Compute = instance.compute
|
compute: Compute = instance.compute
|
||||||
computes = Compute.objects.all().order_by('name')
|
computes = Compute.objects.all().order_by('name')
|
||||||
computes_count = computes.count()
|
computes_count = computes.count()
|
||||||
|
|
@ -59,7 +59,6 @@ def instance(request, pk):
|
||||||
publickeys = UserSSHKey.objects.filter(user_id=request.user.id)
|
publickeys = UserSSHKey.objects.filter(user_id=request.user.id)
|
||||||
keymaps = settings.QEMU_KEYMAPS
|
keymaps = settings.QEMU_KEYMAPS
|
||||||
console_types = AppSettings.objects.get(key="QEMU_CONSOLE_DEFAULT_TYPE").choices_as_list()
|
console_types = AppSettings.objects.get(key="QEMU_CONSOLE_DEFAULT_TYPE").choices_as_list()
|
||||||
#
|
|
||||||
console_form = ConsoleForm(
|
console_form = ConsoleForm(
|
||||||
initial={
|
initial={
|
||||||
'type': instance.console_type,
|
'type': instance.console_type,
|
||||||
|
|
@ -67,7 +66,6 @@ def instance(request, pk):
|
||||||
'password': instance.console_passwd,
|
'password': instance.console_passwd,
|
||||||
'keymap': instance.console_keymap,
|
'keymap': instance.console_keymap,
|
||||||
})
|
})
|
||||||
#
|
|
||||||
console_listen_addresses = settings.QEMU_CONSOLE_LISTEN_ADDRESSES
|
console_listen_addresses = settings.QEMU_CONSOLE_LISTEN_ADDRESSES
|
||||||
bottom_bar = app_settings.VIEW_INSTANCE_DETAIL_BOTTOM_BAR
|
bottom_bar = app_settings.VIEW_INSTANCE_DETAIL_BOTTOM_BAR
|
||||||
allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template
|
allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template
|
||||||
|
|
@ -78,15 +76,6 @@ def instance(request, pk):
|
||||||
except UserInstance.DoesNotExist:
|
except UserInstance.DoesNotExist:
|
||||||
userinstance = None
|
userinstance = None
|
||||||
|
|
||||||
if not request.user.is_superuser:
|
|
||||||
if not userinstance:
|
|
||||||
return redirect(reverse('index'))
|
|
||||||
|
|
||||||
if len(instance.media) != 0:
|
|
||||||
media_iso = sorted(instance.proxy.get_iso_media())
|
|
||||||
else:
|
|
||||||
media_iso = []
|
|
||||||
|
|
||||||
memory_range = [256, 512, 768, 1024, 2048, 3072, 4096, 6144, 8192, 16384]
|
memory_range = [256, 512, 768, 1024, 2048, 3072, 4096, 6144, 8192, 16384]
|
||||||
if instance.memory not in memory_range:
|
if instance.memory not in memory_range:
|
||||||
insort(memory_range, instance.memory)
|
insort(memory_range, instance.memory)
|
||||||
|
|
@ -127,18 +116,11 @@ def instance(request, pk):
|
||||||
vcpu_host = len(instance.vcpu_range)
|
vcpu_host = len(instance.vcpu_range)
|
||||||
memory_host = instance.proxy.get_max_memory()
|
memory_host = instance.proxy.get_max_memory()
|
||||||
bus_host = instance.proxy.get_disk_bus_types(instance.arch, instance.machine)
|
bus_host = instance.proxy.get_disk_bus_types(instance.arch, instance.machine)
|
||||||
# videos_host = instance.proxy.get_video_models(instance.arch, instance.machine)
|
|
||||||
networks_host = sorted(instance.proxy.get_networks())
|
networks_host = sorted(instance.proxy.get_networks())
|
||||||
nwfilters_host = instance.proxy.get_nwfilters()
|
nwfilters_host = instance.proxy.get_nwfilters()
|
||||||
storages_host = sorted(instance.proxy.get_storages(True))
|
storages_host = sorted(instance.proxy.get_storages(True))
|
||||||
net_models_host = instance.proxy.get_network_models()
|
net_models_host = instance.proxy.get_network_models()
|
||||||
|
|
||||||
try:
|
|
||||||
interfaces_host = sorted(instance.proxy.get_ifaces())
|
|
||||||
except Exception as e:
|
|
||||||
addlogmsg(request.user.username, instance.name, e)
|
|
||||||
messages.error(request, e)
|
|
||||||
|
|
||||||
return render(request, 'instance.html', locals())
|
return render(request, 'instance.html', locals())
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -210,18 +192,18 @@ def check_instance(request, vname):
|
||||||
data = {'vname': vname, 'exists': False}
|
data = {'vname': vname, 'exists': False}
|
||||||
if instance:
|
if instance:
|
||||||
data['exists'] = True
|
data['exists'] = True
|
||||||
return HttpResponse(json.dumps(data))
|
return JsonResponse(data)
|
||||||
|
|
||||||
|
|
||||||
def sshkeys(request, vname):
|
def sshkeys(request, pk):
|
||||||
"""
|
"""
|
||||||
:param request:
|
:param request:
|
||||||
:param vname:
|
:param vname:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
|
instance = get_instance(request.user, pk)
|
||||||
instance_keys = []
|
instance_keys = []
|
||||||
userinstances = UserInstance.objects.filter(instance__name=vname)
|
userinstances = UserInstance.objects.filter(instance=instance)
|
||||||
|
|
||||||
for ui in userinstances:
|
for ui in userinstances:
|
||||||
keys = UserSSHKey.objects.filter(user=ui.user)
|
keys = UserSSHKey.objects.filter(user=ui.user)
|
||||||
|
|
@ -239,7 +221,7 @@ def get_instance(user, pk):
|
||||||
'''
|
'''
|
||||||
Check that instance is available for user, if not raise 404
|
Check that instance is available for user, if not raise 404
|
||||||
'''
|
'''
|
||||||
instance = Instance.objects.get(pk=pk)
|
instance = get_object_or_404(Instance, pk=pk)
|
||||||
user_instances = user.userinstance_set.all().values_list('instance', flat=True)
|
user_instances = user.userinstance_set.all().values_list('instance', flat=True)
|
||||||
|
|
||||||
if user.is_superuser or instance.id in user_instances:
|
if user.is_superuser or instance.id in user_instances:
|
||||||
|
|
@ -498,7 +480,6 @@ def resize_disk(request, pk):
|
||||||
if request.user.is_superuser or request.user.is_staff or userinstance.is_change:
|
if request.user.is_superuser or request.user.is_staff or userinstance.is_change:
|
||||||
disks_new = list()
|
disks_new = list()
|
||||||
for disk in disks:
|
for disk in disks:
|
||||||
# input_disk_size = utils.filesizefstr(request.POST.get('disk_size_' + disk['dev'], ''))
|
|
||||||
input_disk_size = int(request.POST.get('disk_size_' + disk['dev'], '0')) * 1073741824
|
input_disk_size = int(request.POST.get('disk_size_' + disk['dev'], '0')) * 1073741824
|
||||||
if input_disk_size > disk['size'] + (64 << 20):
|
if input_disk_size > disk['size'] + (64 << 20):
|
||||||
disk['size_new'] = input_disk_size
|
disk['size_new'] = input_disk_size
|
||||||
|
|
@ -1005,7 +986,7 @@ def add_owner(request, pk):
|
||||||
if app_settings.ALLOW_INSTANCE_MULTIPLE_OWNER == 'False':
|
if app_settings.ALLOW_INSTANCE_MULTIPLE_OWNER == 'False':
|
||||||
check_inst = UserInstance.objects.filter(instance=instance).count()
|
check_inst = UserInstance.objects.filter(instance=instance).count()
|
||||||
|
|
||||||
if check_inst > 1:
|
if check_inst > 0:
|
||||||
messages.error(request, _("Only one owner is allowed and the one already added"))
|
messages.error(request, _("Only one owner is allowed and the one already added"))
|
||||||
else:
|
else:
|
||||||
add_user_inst = UserInstance(instance=instance, user_id=user_id)
|
add_user_inst = UserInstance(instance=instance, user_id=user_id)
|
||||||
|
|
@ -1027,7 +1008,7 @@ def del_owner(request, pk):
|
||||||
return redirect(request.META.get('HTTP_REFERER') + '#users')
|
return redirect(request.META.get('HTTP_REFERER') + '#users')
|
||||||
|
|
||||||
|
|
||||||
@permission_required('instances.clone_instances')
|
@permission_required('instances.clone_instances', raise_exception=True)
|
||||||
def clone(request, pk):
|
def clone(request, pk):
|
||||||
instance = get_instance(request.user, pk)
|
instance = get_instance(request.user, pk)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import re
|
import re
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class AddInterface(forms.Form):
|
class AddInterface(forms.Form):
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block title %}{% trans "Interface" %} - {{ iface }}{% endblock %}
|
{% block title %}{% trans "Interface" %} - {{ iface }}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_heading %}{% trans "Interface" %}: {{ iface }}{% endblock page_heading %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<!-- Page Heading -->
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<h2 class="page-header">{% trans "Interface" %}: {{ iface }}</h2>
|
|
||||||
<ol class="breadcrumb bg-light shadow-sm">
|
<ol class="breadcrumb bg-light shadow-sm">
|
||||||
<li class="breadcrumb-item active">
|
<li class="breadcrumb-item active">
|
||||||
<a href="{% url 'overview' compute.id %}"><i class="fa fa-dashboard"></i> {% trans "Overview" %}</a>
|
<a href="{% url 'overview' compute.id %}"><i class="fa fa-dashboard"></i> {% trans "Overview" %}</a>
|
||||||
|
|
@ -31,9 +33,6 @@
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.row -->
|
|
||||||
|
|
||||||
{% include 'errors_block.html' %}
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<dl class="ml-3 row">
|
<dl class="ml-3 row">
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,16 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
|
|
||||||
{% block title %}{% trans "Interfaces" %} - {{ compute.name }}{% endblock %}
|
{% block title %}{% trans "Interfaces" %} - {{ compute.name }}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_heading%}{% trans "Interfaces" %} - {{ compute.name }}{% endblock page_heading %}
|
||||||
|
|
||||||
|
{% block page_heading_extra %}{% include 'create_iface_block.html' %}{% endblock page_heading_extra %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<!-- Page Heading -->
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
{% include 'create_iface_block.html' %}
|
|
||||||
<h2 class="page-header">{{ compute.name }}</h2>
|
|
||||||
<nav aria-label="breadcrumb">
|
<nav aria-label="breadcrumb">
|
||||||
<ol class="breadcrumb bg-light shadow-sm">
|
<ol class="breadcrumb bg-light shadow-sm">
|
||||||
<li class="breadcrumb-item active">
|
<li class="breadcrumb-item active">
|
||||||
|
|
@ -35,9 +38,6 @@
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.row -->
|
|
||||||
|
|
||||||
{% include 'errors_block.html' %}
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{% if not ifaces_all %}
|
{% if not ifaces_all %}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
from django.contrib import messages
|
||||||
from django.shortcuts import render, get_object_or_404
|
from django.shortcuts import render, get_object_or_404
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
@ -17,7 +18,6 @@ def interfaces(request, compute_id):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ifaces_all = []
|
ifaces_all = []
|
||||||
error_messages = []
|
|
||||||
compute = get_object_or_404(Compute, pk=compute_id)
|
compute = get_object_or_404(Compute, pk=compute_id)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -42,10 +42,10 @@ def interfaces(request, compute_id):
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
else:
|
else:
|
||||||
for msg_err in form.errors.values():
|
for msg_err in form.errors.values():
|
||||||
error_messages.append(msg_err.as_text())
|
messages.error(request, msg_err.as_text())
|
||||||
conn.close()
|
conn.close()
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
error_messages.append(lib_err)
|
messages.error(request, lib_err)
|
||||||
|
|
||||||
return render(request, 'interfaces.html', locals())
|
return render(request, 'interfaces.html', locals())
|
||||||
|
|
||||||
|
|
@ -60,7 +60,6 @@ def interface(request, compute_id, iface):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ifaces_all = []
|
ifaces_all = []
|
||||||
error_messages = []
|
|
||||||
compute = get_object_or_404(Compute, pk=compute_id)
|
compute = get_object_or_404(Compute, pk=compute_id)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -88,6 +87,6 @@ def interface(request, compute_id, iface):
|
||||||
return HttpResponseRedirect(reverse('interfaces', args=[compute_id]))
|
return HttpResponseRedirect(reverse('interfaces', args=[compute_id]))
|
||||||
conn.close()
|
conn.close()
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
error_messages.append(lib_err)
|
messages.error(request, lib_err)
|
||||||
|
|
||||||
return render(request, 'interface.html', locals())
|
return render(request, 'interface.html', locals())
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from django.db.models import Model, CharField, DateTimeField
|
from django.db.models import Model, CharField, DateTimeField
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class Logs(Model):
|
class Logs(Model):
|
||||||
|
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
<div class="center-block">
|
|
||||||
{% if page > 1 %}
|
|
||||||
<a href="{% url 'showlogspage' page|add:"-1" %}">←</a>
|
|
||||||
{% else %}
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
{% if has_next_page %}
|
|
||||||
<a href="{% url 'showlogspage' page|add:"1" %}">→</a>
|
|
||||||
{% else %}
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import re
|
import re
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class AddNetPool(forms.Form):
|
class AddNetPool(forms.Form):
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
|
|
||||||
{% block title %}{% trans "Network" %} - {{ pool }}{% endblock %}
|
{% block title %}{% trans "Network" %} - {{ pool }}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_heading %}{% trans "Network" %}: {{ pool }}{% endblock page_heading %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<!-- Page Heading -->
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<h2 class="page-header">{% trans "Network" %}: {{ pool }}</h2>
|
|
||||||
|
|
||||||
<ol class="breadcrumb bg-light shadow-sm">
|
<ol class="breadcrumb bg-light shadow-sm">
|
||||||
<li class="breadcrumb-item">
|
<li class="breadcrumb-item">
|
||||||
<a href="{% url 'overview' compute.id %}"><i class="fa fa-dashboard"></i> {% trans "Overview" %}</a>
|
<a href="{% url 'overview' compute.id %}"><i class="fa fa-dashboard"></i> {% trans "Overview" %}</a>
|
||||||
|
|
@ -34,9 +35,6 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.row -->
|
|
||||||
|
|
||||||
{% include 'errors_block.html' %}
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<dl class="ml-3 row">
|
<dl class="ml-3 row">
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% block title %}{% trans "Networks" %} - {{ compute.name }}{% endblock %}
|
|
||||||
|
{% block title %}{{ compute.name }} - {% trans "Networks" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_heading %}{{ compute.name }} - {% trans "Networks" %}{% endblock page_heading %}
|
||||||
|
|
||||||
|
{% block page_heading_extra %}{% include 'create_net_block.html' %}{% endblock page_heading_extra %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<!-- Page Heading -->
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12">
|
|
||||||
{% include 'create_net_block.html' %}
|
|
||||||
<h2 class="page-header">{{ compute.name }} - {% trans "Networks" %}</h2>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<nav aria-label="breadcrumb">
|
<nav aria-label="breadcrumb">
|
||||||
|
|
@ -38,9 +37,6 @@
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.row -->
|
|
||||||
|
|
||||||
{% include 'errors_block.html' %}
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{% if not networks %}
|
{% if not networks %}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ from django.contrib import messages
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.shortcuts import get_object_or_404, render
|
from django.shortcuts import get_object_or_404, render
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from libvirt import libvirtError
|
from libvirt import libvirtError
|
||||||
|
|
||||||
from admin.decorators import superuser_only
|
from admin.decorators import superuser_only
|
||||||
|
|
@ -19,8 +19,8 @@ def networks(request, compute_id):
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
error_messages = []
|
|
||||||
compute = get_object_or_404(Compute, pk=compute_id)
|
compute = get_object_or_404(Compute, pk=compute_id)
|
||||||
|
errors = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
conn = wvmNetworks(
|
conn = wvmNetworks(
|
||||||
|
|
@ -41,9 +41,11 @@ def networks(request, compute_id):
|
||||||
data = form.cleaned_data
|
data = form.cleaned_data
|
||||||
if data['name'] in networks:
|
if data['name'] in networks:
|
||||||
msg = _("Network pool name already in use")
|
msg = _("Network pool name already in use")
|
||||||
error_messages.append(msg)
|
messages.error(request, msg)
|
||||||
|
errors = True
|
||||||
if data['forward'] in ['bridge', 'macvtap'] and data['bridge_name'] == '':
|
if data['forward'] in ['bridge', 'macvtap'] and data['bridge_name'] == '':
|
||||||
error_messages.append(_('Please enter bridge/dev name'))
|
messages.error(request, _('Please enter bridge/dev name'))
|
||||||
|
errors = True
|
||||||
if data['subnet']:
|
if data['subnet']:
|
||||||
ipv4 = True
|
ipv4 = True
|
||||||
gateway4, netmask4, dhcp4 = network_size(data['subnet'], data['dhcp4'])
|
gateway4, netmask4, dhcp4 = network_size(data['subnet'], data['dhcp4'])
|
||||||
|
|
@ -51,8 +53,9 @@ def networks(request, compute_id):
|
||||||
ipv6 = True
|
ipv6 = True
|
||||||
gateway6, prefix6, dhcp6 = network_size(data['subnet6'], data['dhcp6'])
|
gateway6, prefix6, dhcp6 = network_size(data['subnet6'], data['dhcp6'])
|
||||||
if prefix6 != '64':
|
if prefix6 != '64':
|
||||||
error_messages.append(_('For libvirt, the IPv6 network prefix must be /64'))
|
messages.error(request, _('For libvirt, the IPv6 network prefix must be /64'))
|
||||||
if not error_messages:
|
errors = True
|
||||||
|
if not errors:
|
||||||
conn.create_network(
|
conn.create_network(
|
||||||
data['name'],
|
data['name'],
|
||||||
data['forward'],
|
data['forward'],
|
||||||
|
|
@ -71,10 +74,10 @@ def networks(request, compute_id):
|
||||||
return HttpResponseRedirect(reverse('network', args=[compute_id, data['name']]))
|
return HttpResponseRedirect(reverse('network', args=[compute_id, data['name']]))
|
||||||
else:
|
else:
|
||||||
for msg_err in form.errors.values():
|
for msg_err in form.errors.values():
|
||||||
error_messages.append(msg_err.as_text())
|
messages.error(request, msg_err.as_text())
|
||||||
conn.close()
|
conn.close()
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
error_messages.append(lib_err)
|
messages.error(request, lib_err)
|
||||||
|
|
||||||
return render(request, 'networks.html', locals())
|
return render(request, 'networks.html', locals())
|
||||||
|
|
||||||
|
|
@ -88,7 +91,6 @@ def network(request, compute_id, pool):
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
error_messages = []
|
|
||||||
compute = get_object_or_404(Compute, pk=compute_id)
|
compute = get_object_or_404(Compute, pk=compute_id)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -125,7 +127,7 @@ def network(request, compute_id, pool):
|
||||||
|
|
||||||
xml = conn._XMLDesc(0)
|
xml = conn._XMLDesc(0)
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
error_messages.append(lib_err)
|
messages.error(request, lib_err)
|
||||||
return HttpResponseRedirect(reverse('networks', args=compute_id))
|
return HttpResponseRedirect(reverse('networks', args=compute_id))
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
|
|
@ -134,31 +136,31 @@ def network(request, compute_id, pool):
|
||||||
conn.start()
|
conn.start()
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
error_messages.append(lib_err)
|
messages.error(request, lib_err)
|
||||||
if 'stop' in request.POST:
|
if 'stop' in request.POST:
|
||||||
try:
|
try:
|
||||||
conn.stop()
|
conn.stop()
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
error_messages.append(lib_err)
|
messages.error(request, lib_err)
|
||||||
if 'delete' in request.POST:
|
if 'delete' in request.POST:
|
||||||
try:
|
try:
|
||||||
conn.delete()
|
conn.delete()
|
||||||
return HttpResponseRedirect(reverse('networks', args=[compute_id]))
|
return HttpResponseRedirect(reverse('networks', args=[compute_id]))
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
error_messages.append(lib_err)
|
messages.error(request, lib_err)
|
||||||
if 'set_autostart' in request.POST:
|
if 'set_autostart' in request.POST:
|
||||||
try:
|
try:
|
||||||
conn.set_autostart(1)
|
conn.set_autostart(1)
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
error_messages.append(lib_err)
|
messages.error(request, lib_err)
|
||||||
if 'unset_autostart' in request.POST:
|
if 'unset_autostart' in request.POST:
|
||||||
try:
|
try:
|
||||||
conn.set_autostart(0)
|
conn.set_autostart(0)
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
error_messages.append(lib_err)
|
messages.error(request, lib_err)
|
||||||
if 'modify_fixed_address' in request.POST:
|
if 'modify_fixed_address' in request.POST:
|
||||||
name = request.POST.get('name', '')
|
name = request.POST.get('name', '')
|
||||||
address = request.POST.get('address', '')
|
address = request.POST.get('address', '')
|
||||||
|
|
@ -174,9 +176,9 @@ def network(request, compute_id, pool):
|
||||||
messages.success(request, _(f"{family.upper()} Fixed Address Operation Completed."))
|
messages.success(request, _(f"{family.upper()} Fixed Address Operation Completed."))
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
error_messages.append(lib_err)
|
messages.error(request, lib_err)
|
||||||
except ValueError as val_err:
|
except ValueError as val_err:
|
||||||
error_messages.append(val_err)
|
messages.error(request, val_err)
|
||||||
if 'delete_fixed_address' in request.POST:
|
if 'delete_fixed_address' in request.POST:
|
||||||
ip = request.POST.get('address', '')
|
ip = request.POST.get('address', '')
|
||||||
family = request.POST.get('family', 'ipv4')
|
family = request.POST.get('family', 'ipv4')
|
||||||
|
|
@ -192,7 +194,7 @@ def network(request, compute_id, pool):
|
||||||
messages.success(request, _(f"{family.upper()} DHCP Range is Changed."))
|
messages.success(request, _(f"{family.upper()} DHCP Range is Changed."))
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
error_messages.append(lib_err)
|
messages.error(request, lib_err)
|
||||||
if 'edit_network' in request.POST:
|
if 'edit_network' in request.POST:
|
||||||
edit_xml = request.POST.get('edit_xml', '')
|
edit_xml = request.POST.get('edit_xml', '')
|
||||||
if edit_xml:
|
if edit_xml:
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
{% block title %}{% trans "NWFilters" %} - {{ compute.name }}{% endblock %}
|
|
||||||
|
{% block title %}{% trans "NWFilter" %}: {{ name }}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_heading %}{% trans "NWFilter" %}: {{ name }}{% endblock page_heading %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<!-- Page Heading -->
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<h3 class="page-header">{% trans "NWFilter" %}: {{ name }}</h3>
|
|
||||||
<ol class="breadcrumb bg-light shadow-sm">
|
<ol class="breadcrumb bg-light shadow-sm">
|
||||||
<li class="breadcrumb-item active">
|
<li class="breadcrumb-item active">
|
||||||
<a href="{% url 'overview' compute.id %}"><i class="fa fa-dashboard"></i> {% trans "Overview" %}</a>
|
<a href="{% url 'overview' compute.id %}"><i class="fa fa-dashboard"></i> {% trans "Overview" %}</a>
|
||||||
|
|
@ -32,11 +34,6 @@
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.row -->
|
|
||||||
|
|
||||||
{% include 'errors_block.html' %}
|
|
||||||
{% include 'messages_block.html' %}
|
|
||||||
|
|
||||||
|
|
||||||
<dl class="ml-3 row">
|
<dl class="ml-3 row">
|
||||||
<dt class="col-4">{% trans "UUID" %}:</dt>
|
<dt class="col-4">{% trans "UUID" %}:</dt>
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,19 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
{% block title %}{% trans "NWFilters" %} - {{ compute.name }}{% endblock %}
|
|
||||||
|
{% block title %}{{ compute.name }} - {% trans "NWFilters" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_heading %}{{ compute.name }} - {% trans "NWFilters" %}{% endblock page_heading %}
|
||||||
|
|
||||||
|
{% block page_heading_extra %}
|
||||||
|
{% include 'create_nwfilter_block.html' %}
|
||||||
|
<div class="float-right search">
|
||||||
|
<input id="filter" class="form-control" type="text" placeholder="{% trans 'Search' %}">
|
||||||
|
</div>
|
||||||
|
{% endblock page_heading_extra %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<!-- Page Heading -->
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12">
|
|
||||||
{% include 'create_nwfilter_block.html' %}
|
|
||||||
<div class="float-right search">
|
|
||||||
<input id="filter" class="form-control" type="text" placeholder="{% trans 'Search' %}">
|
|
||||||
</div>
|
|
||||||
<h2 class="page-header">{{ compute.name }} - {% trans "NWFilters" %}</h2>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<nav aria-label="breadcrumb">
|
<nav aria-label="breadcrumb">
|
||||||
|
|
@ -42,10 +43,6 @@
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.row -->
|
|
||||||
|
|
||||||
{% include 'errors_block.html' %}
|
|
||||||
{% include 'messages_block.html' %}
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
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 admin.decorators import superuser_only
|
||||||
from computes.models import Compute
|
from computes.models import Compute
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.http import HttpResponseRedirect
|
||||||
|
from django.shortcuts import get_object_or_404, render
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from libvirt import libvirtError
|
||||||
from logs.views import addlogmsg
|
from logs.views import addlogmsg
|
||||||
from vrtManager import util
|
from vrtManager import util
|
||||||
from vrtManager.instance import wvmInstance, wvmInstances
|
from vrtManager.instance import wvmInstance, wvmInstances
|
||||||
|
|
@ -20,7 +19,6 @@ def nwfilters(request, compute_id):
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
error_messages = []
|
|
||||||
nwfilters_all = []
|
nwfilters_all = []
|
||||||
compute = get_object_or_404(Compute, pk=compute_id)
|
compute = get_object_or_404(Compute, pk=compute_id)
|
||||||
|
|
||||||
|
|
@ -51,7 +49,7 @@ def nwfilters(request, compute_id):
|
||||||
conn.create_nwfilter(xml)
|
conn.create_nwfilter(xml)
|
||||||
addlogmsg(request.user.username, compute.hostname, msg)
|
addlogmsg(request.user.username, compute.hostname, msg)
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
error_messages.append(lib_err)
|
messages.error(request, lib_err)
|
||||||
addlogmsg(request.user.username, compute.hostname, lib_err)
|
addlogmsg(request.user.username, compute.hostname, lib_err)
|
||||||
|
|
||||||
if 'del_nwfilter' in request.POST:
|
if 'del_nwfilter' in request.POST:
|
||||||
|
|
@ -69,7 +67,7 @@ def nwfilters(request, compute_id):
|
||||||
if name in dom_filterrefs:
|
if name in dom_filterrefs:
|
||||||
in_use = True
|
in_use = True
|
||||||
msg = _(f"NWFilter is in use by {inst}. Cannot be deleted.")
|
msg = _(f"NWFilter is in use by {inst}. Cannot be deleted.")
|
||||||
error_messages.append(msg)
|
messages.error(request, msg)
|
||||||
addlogmsg(request.user.username, compute.hostname, msg)
|
addlogmsg(request.user.username, compute.hostname, msg)
|
||||||
i_conn.close()
|
i_conn.close()
|
||||||
break
|
break
|
||||||
|
|
@ -93,16 +91,15 @@ def nwfilters(request, compute_id):
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
error_messages.append(lib_err)
|
messages.error(request, lib_err)
|
||||||
addlogmsg(request.user.username, compute.hostname, lib_err)
|
addlogmsg(request.user.username, compute.hostname, lib_err)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
error_messages.append(err)
|
messages.error(request, err)
|
||||||
addlogmsg(request.user.username, compute.hostname, err)
|
addlogmsg(request.user.username, compute.hostname, err)
|
||||||
|
|
||||||
return render(request, 'nwfilters.html', {
|
return render(request, 'nwfilters.html', {
|
||||||
'error_messages': error_messages,
|
|
||||||
'nwfilters': nwfilters_all,
|
'nwfilters': nwfilters_all,
|
||||||
'compute': compute
|
'compute': compute,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -113,7 +110,6 @@ def nwfilter(request, compute_id, nwfltr):
|
||||||
:param nwfltr:
|
:param nwfltr:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
error_messages = []
|
|
||||||
nwfilters_all = []
|
nwfilters_all = []
|
||||||
compute = get_object_or_404(Compute, pk=compute_id)
|
compute = get_object_or_404(Compute, pk=compute_id)
|
||||||
|
|
||||||
|
|
@ -194,8 +190,8 @@ def nwfilter(request, compute_id, nwfltr):
|
||||||
conn.close()
|
conn.close()
|
||||||
nwfilter.close()
|
nwfilter.close()
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
error_messages.append(lib_err)
|
messages.error(request, lib_err)
|
||||||
except Exception as error_msg:
|
except Exception as error_msg:
|
||||||
error_messages.append(error_msg)
|
messages.error(request, error_msg)
|
||||||
|
|
||||||
return render(request, 'nwfilter.html', locals())
|
return render(request, 'nwfilter.html', locals())
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,19 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
{% block title %}{% trans "Secrets" %} - {{ compute.name }}{% endblock %}
|
{% block title %}{% trans "Secrets" %} - {{ compute.name }}{% endblock %}
|
||||||
|
|
||||||
{% block style %}
|
{% block style %}
|
||||||
<link rel="stylesheet" href="{% static "css/sortable-theme-bootstrap.css" %}" />
|
<link rel="stylesheet" href="{% static "css/sortable-theme-bootstrap.css" %}" />
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block page_heading %}{{ compute }} - {% trans "Secrets" %}{% endblock page_heading %}
|
||||||
|
|
||||||
|
{% block page_heading_extra %}{% include 'create_secret_block.html' %}{% endblock page_heading_extra %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<!-- Page Heading -->
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
{% include 'create_secret_block.html' %}
|
<h2 class="page-header"></h2>
|
||||||
<h2 class="page-header">{% trans "Secrets" %}</h2>
|
|
||||||
<nav aria-label="breadcrumb">
|
<nav aria-label="breadcrumb">
|
||||||
<ol class="breadcrumb bg-light shadow-sm">
|
<ol class="breadcrumb bg-light shadow-sm">
|
||||||
<li class="breadcrumb-item active">
|
<li class="breadcrumb-item active">
|
||||||
|
|
@ -38,9 +42,6 @@
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.row -->
|
|
||||||
|
|
||||||
{% include 'errors_block.html' %}
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{% if not secrets_all %}
|
{% if not secrets_all %}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,12 @@
|
||||||
|
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 admin.decorators import superuser_only
|
||||||
from computes.models import Compute
|
from computes.models import Compute
|
||||||
from secrets.forms import AddSecret
|
from django.contrib import messages
|
||||||
|
from django.http import HttpResponseRedirect
|
||||||
|
from django.shortcuts import get_object_or_404, render
|
||||||
|
from libvirt import (VIR_SECRET_USAGE_TYPE_CEPH, VIR_SECRET_USAGE_TYPE_ISCSI, VIR_SECRET_USAGE_TYPE_NONE,
|
||||||
|
VIR_SECRET_USAGE_TYPE_TLS, VIR_SECRET_USAGE_TYPE_VOLUME, libvirtError)
|
||||||
from vrtManager.secrets import wvmSecrets
|
from vrtManager.secrets import wvmSecrets
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -24,7 +19,6 @@ def secrets(request, compute_id):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
secrets_all = []
|
secrets_all = []
|
||||||
error_messages = []
|
|
||||||
compute = get_object_or_404(Compute, pk=compute_id)
|
compute = get_object_or_404(Compute, pk=compute_id)
|
||||||
secret_usage_types = {
|
secret_usage_types = {
|
||||||
VIR_SECRET_USAGE_TYPE_NONE: "none",
|
VIR_SECRET_USAGE_TYPE_NONE: "none",
|
||||||
|
|
@ -59,11 +53,12 @@ def secrets(request, compute_id):
|
||||||
data['ephemeral'],
|
data['ephemeral'],
|
||||||
data['private'],
|
data['private'],
|
||||||
data['usage_type'],
|
data['usage_type'],
|
||||||
data['data'])
|
data['data'],
|
||||||
|
)
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
else:
|
else:
|
||||||
for msg_err in form.errors.values():
|
for msg_err in form.errors.values():
|
||||||
error_messages.append(msg_err.as_text())
|
messages.error(request, msg_err.as_text())
|
||||||
if 'delete' in request.POST:
|
if 'delete' in request.POST:
|
||||||
uuid = request.POST.get('uuid', '')
|
uuid = request.POST.get('uuid', '')
|
||||||
conn.delete_secret(uuid)
|
conn.delete_secret(uuid)
|
||||||
|
|
@ -74,9 +69,9 @@ def secrets(request, compute_id):
|
||||||
try:
|
try:
|
||||||
conn.set_secret_value(uuid, value)
|
conn.set_secret_value(uuid, value)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
error_messages.append(err)
|
messages.error(request, err)
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
except libvirtError as err:
|
except libvirtError as err:
|
||||||
error_messages.append(err)
|
messages.error(request, err)
|
||||||
|
|
||||||
return render(request, 'secrets.html', locals())
|
return render(request, 'secrets.html', locals())
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import re
|
import re
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class AddStgPool(forms.Form):
|
class AddStgPool(forms.Form):
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,19 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
{% block title %}{% trans "Storage" %} - {{ pool }}{% endblock %}
|
{% block title %}{{ compute }} - {% trans "Storage" %}: {{ pool }}{% endblock %}
|
||||||
{% block style %}
|
{% block style %}
|
||||||
<link rel="stylesheet" href="{% static "css/sortable-theme-bootstrap.css" %}"/>
|
<link rel="stylesheet" href="{% static "css/sortable-theme-bootstrap.css" %}"/>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<!-- Page Heading -->
|
{% block page_heading %}{{ compute }} - {% trans "Storage" %}: {{ pool }}{% endblock page_heading %}
|
||||||
|
|
||||||
|
{% block page_heading_extra %}{% include 'create_stg_vol_block.html' %}{% endblock page_heading_extra %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
{% include 'create_stg_vol_block.html' %}
|
<h2 class="page-header"></h2>
|
||||||
<h2 class="page-header">{% trans "Storage" %}: {{ pool }}</h2>
|
|
||||||
<ol class="breadcrumb bg-light shadow-sm">
|
<ol class="breadcrumb bg-light shadow-sm">
|
||||||
<li class="breadcrumb-item active">
|
<li class="breadcrumb-item active">
|
||||||
<a href="{% url 'overview' compute.id %}"><i class="fa fa-dashboard"></i> {% trans "Overview" %}</a>
|
<a href="{% url 'overview' compute.id %}"><i class="fa fa-dashboard"></i> {% trans "Overview" %}</a>
|
||||||
|
|
@ -37,9 +39,6 @@
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.row -->
|
|
||||||
|
|
||||||
{% include 'errors_block.html' %}
|
|
||||||
|
|
||||||
<dl class="ml-3 row">
|
<dl class="ml-3 row">
|
||||||
<dt class="col-6">{% trans "Pool name" %}</dt>
|
<dt class="col-6">{% trans "Pool name" %}</dt>
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% block title %}{% trans "Storages" %} - {{ compute.name }}{% endblock %}
|
|
||||||
|
{% block title %}{{ compute.name }} - {% trans "Storages" %}{% endblock %}
|
||||||
|
|
||||||
|
{% block page_heading %}{{ compute.name }} - {% trans "Storages" %}{% endblock page_heading %}
|
||||||
|
|
||||||
|
{% block page_heading_extra %}{% include 'create_stg_block.html' %}{% endblock page_heading_extra %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<!-- Page Heading -->
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12">
|
|
||||||
{% include 'create_stg_block.html' %}
|
|
||||||
<h2 class="page-header">{{ compute.name }} - {% trans "Storages" %}</h2>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<nav aria-label="breadcrumb">
|
<nav aria-label="breadcrumb">
|
||||||
|
|
@ -38,10 +37,6 @@
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- /.row -->
|
|
||||||
|
|
||||||
{% include 'errors_block.html' %}
|
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{% if not storages %}
|
{% if not storages %}
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ from django.contrib import messages
|
||||||
from django.http import HttpResponse, HttpResponseRedirect
|
from django.http import HttpResponse, HttpResponseRedirect
|
||||||
from django.shortcuts import get_object_or_404, redirect, render
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from libvirt import libvirtError
|
from libvirt import libvirtError
|
||||||
|
|
||||||
from admin.decorators import superuser_only
|
from admin.decorators import superuser_only
|
||||||
|
|
@ -23,8 +23,8 @@ def storages(request, compute_id):
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
error_messages = []
|
|
||||||
compute = get_object_or_404(Compute, pk=compute_id)
|
compute = get_object_or_404(Compute, pk=compute_id)
|
||||||
|
errors = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
conn = wvmStorages(compute.hostname, compute.login, compute.password, compute.type)
|
conn = wvmStorages(compute.hostname, compute.login, compute.password, compute.type)
|
||||||
|
|
@ -38,15 +38,18 @@ def storages(request, compute_id):
|
||||||
data = form.cleaned_data
|
data = form.cleaned_data
|
||||||
if data['name'] in storages:
|
if data['name'] in storages:
|
||||||
msg = _("Pool name already use")
|
msg = _("Pool name already use")
|
||||||
error_messages.append(msg)
|
messages.error(request, msg)
|
||||||
|
errors = True
|
||||||
if data['stg_type'] == 'rbd':
|
if data['stg_type'] == 'rbd':
|
||||||
if not data['secret']:
|
if not data['secret']:
|
||||||
msg = _("You need create secret for pool")
|
msg = _("You need create secret for pool")
|
||||||
error_messages.append(msg)
|
messages.error(request, msg)
|
||||||
|
errors = True
|
||||||
if not data['ceph_pool'] and not data['ceph_host'] and not data['ceph_user']:
|
if not data['ceph_pool'] and not data['ceph_host'] and not data['ceph_user']:
|
||||||
msg = _("You need input all fields for creating ceph pool")
|
msg = _("You need input all fields for creating ceph pool")
|
||||||
error_messages.append(msg)
|
messages.error(request, msg)
|
||||||
if not error_messages:
|
errors = True
|
||||||
|
if not errors:
|
||||||
if data['stg_type'] == 'rbd':
|
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'])
|
data['ceph_user'], data['secret'])
|
||||||
|
|
@ -58,10 +61,10 @@ def storages(request, compute_id):
|
||||||
return HttpResponseRedirect(reverse('storage', args=[compute_id, data['name']]))
|
return HttpResponseRedirect(reverse('storage', args=[compute_id, data['name']]))
|
||||||
else:
|
else:
|
||||||
for msg_err in form.errors.values():
|
for msg_err in form.errors.values():
|
||||||
error_messages.append(msg_err.as_text())
|
messages.error(request, msg_err.as_text())
|
||||||
conn.close()
|
conn.close()
|
||||||
except libvirtError as lib_err:
|
except libvirtError as lib_err:
|
||||||
error_messages.append(lib_err)
|
messages.error(request, lib_err)
|
||||||
|
|
||||||
return render(request, 'storages.html', locals())
|
return render(request, 'storages.html', locals())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,15 +40,16 @@
|
||||||
<div class"row">
|
<div class"row">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<div class="float-right">
|
<div class="float-right">
|
||||||
{% block page_header_extra %}
|
{% block page_heading_extra %}
|
||||||
{% endblock page_header_extra %}
|
{% endblock page_heading_extra %}
|
||||||
</div>
|
</div>
|
||||||
<h3 class="page-header">
|
<h3 class="page-header">
|
||||||
{% block page_header %}
|
{% block page_heading %}
|
||||||
{% endblock page_header %}
|
{% endblock page_heading %}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<hr>
|
||||||
{% bootstrap_messages %}
|
{% bootstrap_messages %}
|
||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
{% block title %}{{ title }}{% endblock %}
|
{% block title %}{{ title }}{% endblock %}
|
||||||
|
|
||||||
{% block page_header %}{{ title }}{% endblock page_header %}
|
{% block page_heading %}{{ title }}{% endblock page_heading %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
{% block title %}{{ title }}{% endblock %}
|
{% block title %}{{ title }}{% endblock %}
|
||||||
|
|
||||||
{% block page_header %}{{ title }}{% endblock page_header %}
|
{% block page_heading %}{{ title }}{% endblock page_heading %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="card">
|
<div class="card">
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
{% load i18n %}
|
|
||||||
{% if error_messages %}
|
|
||||||
{% for error in error_messages %}
|
|
||||||
<!-- Error Messages -->
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12">
|
|
||||||
<div class="alert alert-danger alert-dismissible" role="alert">
|
|
||||||
<strong>{% trans 'Error' %}:</strong> {{ error }}
|
|
||||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- /.row -->
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
{% load i18n %}
|
|
||||||
{% if messages %}
|
|
||||||
{% for message in messages %}
|
|
||||||
<!-- Success Messages -->
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-12">
|
|
||||||
<div class="alert alert-success alert-dismissible" role="alert">
|
|
||||||
<strong>{% trans 'Success' %}:</strong> {{ message }}
|
|
||||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- /.row -->
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from libvirt import libvirtError
|
from libvirt import libvirtError
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue