Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
83ac067
Merge branch 'patch-2'
Oct 15, 2015
164c9a9
order Compute objects by name
honza801 Nov 13, 2015
8f2f95e
cloning instance with lvm disk also clones the disk and sets the corr…
honza801 Nov 13, 2015
04f3a76
resize disk image option added
honza801 Nov 24, 2015
cd787c3
Merge branch 'master' of github.com:honza801/webvirtcloud
honza801 Nov 24, 2015
35369ed
Fixed Checking KVM
retspen Nov 27, 2015
6dbd6e5
pip installing packages need gcc and pkg-config on debian/ubuntu
honza801 Dec 21, 2015
decd5ab
add remoteuser auth middleware classes
honza801 Dec 22, 2015
f8c08cb
wsgi.py customized for use mod_wsgi with apache module
honza801 Dec 22, 2015
ae4fdce
added class MyRemoteUserBackend(RemoteUserBackend) giving all authent…
honza801 Dec 22, 2015
dac974d
request.user.is_authenticated() substitued for @login_required decorator
honza801 Dec 22, 2015
0eb60b1
ignore novnc certificate (console/cert.pem)
honza801 Dec 28, 2015
1499af1
upgrade websockify 0.6.0 to 0.7.0
honza801 Dec 28, 2015
50ddda9
settings tab for changing devices/interface/source/bridge added
honza801 Jan 14, 2016
6151792
allow multiple owners of single instance. this is controlled by setti…
honza801 Jan 15, 2016
ca328a7
instances/templates/instance.html checkbox delete_disk default checked
honza801 Jan 15, 2016
d036d58
.gitignore: tags
honza801 Jan 19, 2016
8deb844
adding new instance to user checks existing instances assigned to user
honza801 Jan 19, 2016
d4fa71f
default true: live migration and delete original
honza801 Jan 20, 2016
4ab8561
correct value=true of checked checkboxes
honza801 Jan 20, 2016
646bdbb
Added is_template attribute to instances. If true, instance cannot be…
honza801 Jan 20, 2016
a34c55d
clone instance fixes mac address not separated by :, to correct forma…
honza801 Jan 29, 2016
323e0a1
show_clone_disk generates cloned images name with "-*" suffix. fe: vn…
honza801 Feb 8, 2016
33916c6
instance/clone: changing clone name input changes disk image name acc…
honza801 Feb 8, 2016
39f3c9e
instance/clone added Guess mac address button. search for mac address…
honza801 Feb 8, 2016
71c6161
accounts/edit added is_staff and is_superuser checkboxes
honza801 Feb 9, 2016
96982ce
instance/settings: inputs renamed according to action type (net -> cl…
honza801 Feb 10, 2016
a1d5ede
guess_mac_address reads /srv/webvirtcloud/dhcpd.conf
honza801 Feb 11, 2016
2958a21
instance/check_instance service endpoint added. checks for existing i…
honza801 Feb 11, 2016
16510de
instance/clone block new instance creating if instance with same name…
honza801 Feb 11, 2016
510e0e6
guess_mac checks for existing dhcp_file
honza801 Feb 11, 2016
2ceb456
section #template renamed to #options, added title and description fi…
honza801 Feb 23, 2016
e1b4fdf
instances display virtual title under name
honza801 Feb 23, 2016
679f84f
template/instance: correct placement of options tab panel div, should…
honza801 Feb 24, 2016
6c4a3a9
instance/clone view: generation of clone_data algorithm enhanced
honza801 Feb 24, 2016
2aa81cc
instance/clone adds title and description input fields
honza801 Feb 24, 2016
fc56e66
add migration for new column details for hypervisor.
andrem Mar 18, 2016
b6350e1
add details for local socket
andrem Mar 18, 2016
9832e66
account create_user_instance form sorts instances by name
honza801 Mar 21, 2016
c2b3938
add instances/migrations/0002_instance_is_template.py
honza801 Mar 22, 2016
78dcb10
.gitignore dhcpd.*
honza801 Mar 22, 2016
de5cb19
class UserAddForm: remove is_staff, is_superuser
honza801 Mar 23, 2016
317c2a8
user can now clone instances, admin can specify user quotas (instance…
honza801 Mar 23, 2016
6afcd00
logs view adds paging ability
honza801 Mar 23, 2016
027bbbc
Merge remote-tracking branch 'andrem/master'
honza801 Mar 23, 2016
c51e986
clone check_user_quota correct application logic
honza801 Mar 23, 2016
7cdac17
instances list block poweron when is_template for normal users
honza801 Mar 23, 2016
738993d
bugfix: instances list block poweron when is_template for normal users
honza801 Mar 23, 2016
2703011
account max mamory label Max memory (MB), added MB
honza801 Mar 23, 2016
8148620
instances.views.check_user_quota correct cpu/memory sum
honza801 Mar 23, 2016
bc0552e
not superuser delete instance causes delete for all corresponding use…
honza801 Mar 23, 2016
1e84dcb
instance resize check_user_quota correct cpu/memory resize amount. on…
honza801 Mar 23, 2016
16ef164
correct instance summary display after unsuccessfull resize
honza801 Mar 23, 2016
e9e62e3
instance templates show clone button instead of poweron on instances …
honza801 Mar 23, 2016
6546fa2
show instance title in instances view for non superuser
honza801 Mar 24, 2016
f8e681d
added user disk quota limit
honza801 Mar 31, 2016
0e7c5c2
fix instance compute node after migration
honza801 Apr 21, 2016
db1ab88
Merge remote-tracking branch 'retspen/master'
honza801 Apr 21, 2016
2552983
set default UserAttributes to instances=1, vcpus=1, memory=2048, disk=20
honza801 Apr 26, 2016
8de4c6b
/accounts view creates userattributes automatically
honza801 Apr 26, 2016
fc71884
please wait dialog added on migrate/clone event
honza801 Apr 26, 2016
380cc2d
wvmInstance._set_options options.get(o) returns unicode, so cannot be…
honza801 Apr 27, 2016
e45c712
add instance/options/users tab. lists all owners of the instance
honza801 Apr 28, 2016
e966e6c
add user information per instance on the instances list
honza801 May 2, 2016
99bd693
add js.cookie.js to base.html
honza801 May 6, 2016
c4ae3d2
instances filter stores filter value into cookie and auto-fills/appli…
honza801 May 6, 2016
9327cf3
accounts view sorts users by username
honza801 May 6, 2016
572f7b1
instances_filter cookie expires after 1 day
honza801 May 6, 2016
0b80b03
add refresh button into instance view
honza801 May 12, 2016
f484598
add guess button for cloned instance name. this reads dhcp conf and u…
honza801 May 27, 2016
3666ff0
settings.ALLOW_EMPTY_PASSWORD added. allows to create user withnout p…
honza801 Jun 2, 2016
14e8418
Fix typos
May 30, 2016
08cc199
guess_clone_name fix. should check hostname, not fqdn.
honza801 Jun 8, 2016
9e294ad
Security Bug: No external Connections
QDaniel Jul 13, 2016
01fc85e
listen 127.0.0.1
QDaniel Jul 21, 2016
29b722f
Merge branch 'master' of https://github.com/honza801/webvirtcloud
Jul 29, 2016
525d42a
instances/views.py check instance name, alloweed r^[a-zA-Z0-9-]+$
honza801 Sep 6, 2016
ed4cb86
Merge remote-tracking branch 'qdaniel/master'
honza801 Sep 12, 2016
a3a572a
Fixed: Conflicting migrations detected (0004_userinstance_is_vnc, 000…
honza801 Sep 12, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ venv
.DS_*
*.pyc
db.sqlite3
console/cert.pem
tags
dhcpd.*
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ WebVirtCloud is a virtualization web interface for admins and users. It can dele
### Install WebVirtCloud panel (Ubuntu)

```bash
sudo apt-get -y install git python-virtualenv python-dev libxml2-dev libvirt-dev zlib1g-dev nginx supervisor libsasl2-modules
sudo apt-get -y install git python-virtualenv python-dev libxml2-dev libvirt-dev zlib1g-dev nginx supervisor libsasl2-modules gcc pkg-config
git clone https://github.com/retspen/webvirtcloud
cd webvirtcloud
sudo cp conf/supervisor/webvirtcloud.conf /etc/supervisor/conf.d
Expand Down Expand Up @@ -185,6 +185,12 @@ webvirtcloud RUNNING pid 24185, uptime 2:59:14

```

#### Apache mod_wsgi configuration
```
WSGIDaemonProcess webvirtcloud threads=2 maximum-requests=1000 display-name=webvirtcloud
WSGIScriptAlias / /srv/webvirtcloud/webvirtcloud/wsgi.py
```

#### Install final required packages for libvirtd and others on Host Server
```bash
wget -O - https://clck.ru/9V9fH | sudo sh
Expand Down
7 changes: 7 additions & 0 deletions accounts/backends.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from django.contrib.auth.backends import RemoteUserBackend

class MyRemoteUserBackend(RemoteUserBackend):
def configure_user(self, user):
user.is_superuser = True
return user

3 changes: 2 additions & 1 deletion accounts/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
from django import forms
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User
from django.conf import settings


class UserAddForm(forms.Form):
name = forms.CharField(label="Name",
error_messages={'required': _('No User name has been entered')},
max_length=20)
password = forms.CharField(required=True, error_messages={'required': _('No password has been entered')},)
password = forms.CharField(required=not settings.ALLOW_EMPTY_PASSWORD, error_messages={'required': _('No password has been entered')},)

def clean_name(self):
name = self.cleaned_data['name']
Expand Down
26 changes: 26 additions & 0 deletions accounts/migrations/0004_userattributes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations
from django.conf import settings


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('accounts', '0003_usersshkey'),
]

operations = [
migrations.CreateModel(
name='UserAttributes',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('max_instances', models.IntegerField(default=0)),
('max_cpus', models.IntegerField(default=0)),
('max_memory', models.IntegerField(default=0)),
('user', models.OneToOneField(to=settings.AUTH_USER_MODEL)),
],
),
]
19 changes: 19 additions & 0 deletions accounts/migrations/0005_userattributes_can_clone_instances.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations


class Migration(migrations.Migration):

dependencies = [
('accounts', '0004_userattributes'),
]

operations = [
migrations.AddField(
model_name='userattributes',
name='can_clone_instances',
field=models.BooleanField(default=False),
),
]
19 changes: 19 additions & 0 deletions accounts/migrations/0006_userattributes_max_disk_size.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations


class Migration(migrations.Migration):

dependencies = [
('accounts', '0005_userattributes_can_clone_instances'),
]

operations = [
migrations.AddField(
model_name='userattributes',
name='max_disk_size',
field=models.IntegerField(default=0),
),
]
34 changes: 34 additions & 0 deletions accounts/migrations/0007_auto_20160426_0635.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('accounts', '0006_userattributes_max_disk_size'),
]

operations = [
migrations.AlterField(
model_name='userattributes',
name='max_cpus',
field=models.IntegerField(default=1),
),
migrations.AlterField(
model_name='userattributes',
name='max_disk_size',
field=models.IntegerField(default=20),
),
migrations.AlterField(
model_name='userattributes',
name='max_instances',
field=models.IntegerField(default=1),
),
migrations.AlterField(
model_name='userattributes',
name='max_memory',
field=models.IntegerField(default=2048),
),
]
15 changes: 15 additions & 0 deletions accounts/migrations/0008_merge.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('accounts', '0004_userinstance_is_vnc'),
('accounts', '0007_auto_20160426_0635'),
]

operations = [
]
11 changes: 11 additions & 0 deletions accounts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,14 @@ class UserSSHKey(models.Model):

def __unicode__(self):
return self.keyname

class UserAttributes(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
can_clone_instances = models.BooleanField(default=False)
max_instances = models.IntegerField(default=1)
max_cpus = models.IntegerField(default=1)
max_memory = models.IntegerField(default=2048)
max_disk_size = models.IntegerField(default=20)

def __unicode__(self):
return self.user.username
44 changes: 43 additions & 1 deletion accounts/templates/accounts.html
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,48 @@ <h4 class="modal-title">{% trans "Edit user info" %}</h4>
<input type="password" name="user_pass" class="form-control" value="">
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-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">
<label class="col-sm-4 control-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">
<label class="col-sm-4 control-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">
<label class="col-sm-4 control-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">
<label class="col-sm-4 control-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">
<label class="col-sm-4 control-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">
<label class="col-sm-4 control-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="pull-left btn btn-danger" name="delete">
Expand Down Expand Up @@ -99,4 +141,4 @@ <h4 class="modal-title">{% trans "Edit user info" %}</h4>
{% endfor %}
{% endif %}
</div>
{% endblock %}
{% endblock %}
4 changes: 2 additions & 2 deletions accounts/templates/create_user_block.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ <h4 class="modal-title">{% trans "Add New User" %}</h4>
<div class="form-group">
<label class="col-sm-4 control-label">{% trans "Password" %}</label>
<div class="col-sm-6">
<input type="password" class="form-control" name="password" placeholder="*******" required>
<input type="password" class="form-control" name="password" placeholder="*******" {% if not allow_empty_password %}required{% endif %}>
</div>
</div>
</div>
Expand All @@ -35,4 +35,4 @@ <h4 class="modal-title">{% trans "Add New User" %}</h4>
</div> <!-- /.modal-content -->
</div> <!-- /.modal-dialog -->
</div> <!-- /.modal -->
{% endif %}
{% endif %}
51 changes: 36 additions & 15 deletions accounts/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,19 @@
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User
from accounts.models import UserInstance, UserSSHKey
from django.contrib.auth.decorators import login_required
from accounts.models import *
from instances.models import Instance
from accounts.forms import UserAddForm
from django.conf import settings


@login_required
def profile(request):
"""
:param request:
:return:
"""
if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('index'))

error_messages = []
user = User.objects.get(id=request.user.id)
Expand Down Expand Up @@ -63,21 +64,28 @@ def profile(request):
return HttpResponseRedirect(request.get_full_path())
return render(request, 'profile.html', locals())


@login_required
def accounts(request):
"""
:param request:
:return:
"""

if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('index'))
def create_missing_userattributes(users):
for user in users:
try:
userattributes = user.userattributes
except UserAttributes.DoesNotExist:
userattributes = UserAttributes(user=user)
userattributes.save()

if not request.user.is_superuser:
return HttpResponseRedirect(reverse('index'))

error_messages = []
users = User.objects.filter(is_staff=False, is_superuser=False)
users = User.objects.all().order_by('username')
create_missing_userattributes(users)
allow_empty_password = settings.ALLOW_EMPTY_PASSWORD

if request.method == 'POST':
if 'create' in request.POST:
Expand All @@ -96,7 +104,17 @@ def accounts(request):
user_pass = request.POST.get('user_pass', '')
user_edit = User.objects.get(id=user_id)
user_edit.set_password(user_pass)
user_edit.is_staff = request.POST.get('user_is_staff', False)
user_edit.is_superuser = request.POST.get('user_is_superuser', False)
user_edit.save()

userattributes = user_edit.userattributes
userattributes.can_clone_instances = request.POST.get('userattributes_can_clone_instances', False)
userattributes.max_instances = request.POST.get('userattributes_max_instances', 0)
userattributes.max_cpus = request.POST.get('userattributes_max_cpus', 0)
userattributes.max_memory = request.POST.get('userattributes_max_memory', 0)
userattributes.max_disk_size = request.POST.get('userattributes_max_disk_size', 0)
userattributes.save()
return HttpResponseRedirect(request.get_full_path())
if 'block' in request.POST:
user_id = request.POST.get('user_id', '')
Expand All @@ -123,22 +141,20 @@ def accounts(request):
return render(request, 'accounts.html', locals())


@login_required
def account(request, user_id):
"""
:param request:
:return:
"""

if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('index'))

if not request.user.is_superuser:
return HttpResponseRedirect(reverse('index'))

error_messages = []
user = User.objects.get(id=user_id)
user_insts = UserInstance.objects.filter(user_id=user_id)
instances = Instance.objects.all()
instances = Instance.objects.all().order_by('name')

if user.username == request.user.username:
return HttpResponseRedirect(reverse('profile'))
Expand All @@ -162,12 +178,17 @@ def account(request, user_id):
return HttpResponseRedirect(request.get_full_path())
if 'add' in request.POST:
inst_id = request.POST.get('inst_id', '')
try:
check_inst = UserInstance.objects.get(instance_id=int(inst_id))

if settings.ALLOW_INSTANCE_MULTIPLE_OWNER:
check_inst = UserInstance.objects.filter(instance_id=int(inst_id), user_id=int(user_id))
else:
check_inst = UserInstance.objects.filter(instance_id=int(inst_id))

if check_inst:
msg = _("Instance already added")
error_messages.append(msg)
except UserInstance.DoesNotExist:
add_user_inst = UserInstance(instance_id=int(inst_id), user_id=user_id)
else:
add_user_inst = UserInstance(instance_id=int(inst_id), user_id=int(user_id))
add_user_inst.save()
return HttpResponseRedirect(request.get_full_path())

Expand Down
2 changes: 2 additions & 0 deletions computes/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ def clean_hostname(self):
class ComputeAddSocketForm(forms.Form):
name = forms.CharField(error_messages={'required': _('No hostname has been entered')},
max_length=20)
details = forms.CharField(error_messages={'required': _('No details has been entred')},
max_length=50)

def clean_name(self):
name = self.cleaned_data['name']
Expand Down
Loading