From 4d40de1b558c183afd8214f6ebbc394b161915a9 Mon Sep 17 00:00:00 2001 From: catborise Date: Mon, 16 Mar 2020 16:59:45 +0300 Subject: [PATCH 1/8] Python3 & Django 2.2 Migration - Fix & Updates --- .gitignore | 1 + .travis.yml | 4 +- Dockerfile | 10 +- README.md | 52 +- Vagrantfile | 17 +- accounts/forms.py | 3 +- accounts/migrations/0001_initial.py | 42 +- .../migrations/0002_auto_20150325_0846.py | 24 - accounts/migrations/0003_usersshkey.py | 25 - accounts/migrations/0004_userattributes.py | 26 - .../migrations/0004_userinstance_is_vnc.py | 19 - ...0005_userattributes_can_clone_instances.py | 19 - .../0006_userattributes_max_disk_size.py | 19 - .../migrations/0007_auto_20160426_0635.py | 34 - accounts/migrations/0008_merge.py | 15 - .../migrations/0009_auto_20171026_0805.py | 19 - .../migrations/0010_auto_20180625_1236.py | 35 - .../migrations/0011_auto_20180625_1313.py | 36 - .../migrations/0012_auto_20180625_1331.py | 37 - .../migrations/0013_auto_20180625_1358.py | 37 - .../migrations/0014_auto_20180808_1436.py | 36 - .../migrations/0015_auto_20180808_1449.py | 22 - accounts/models.py | 39 +- accounts/templates/account.html | 14 +- accounts/urls.py | 10 +- computes/forms.py | 6 +- computes/migrations/0001_initial.py | 19 +- computes/migrations/0002_compute_details.py | 18 - .../migrations/0003_auto_20200121_1523.py | 30 - computes/models.py | 16 +- computes/urls.py | 41 +- conf/daemon/gstfsd | 12 +- conf/requirements.txt | 9 +- conf/runit/secret_generator.py | 2 +- conf/supervisor/gstfsd.conf | 2 +- conf/supervisor/webvirtcloud.conf | 2 +- console/novncd | 38 +- console/templates/console-base.html | 1 - console/templates/console-spice-full.html | 196 +- console/templates/console-spice-lite.html | 131 +- console/tunnel.py | 3 +- console/views.py | 2 +- create/forms.py | 1 - create/migrations/0001_initial.py | 12 +- ...to_20150325_0921.py => 0002_addFlavors.py} | 5 +- create/models.py | 12 +- create/templates/create_instance_w1.html | 2 +- create/templates/create_instance_w2.html | 4 +- create/views.py | 17 +- dev/requirements.txt | 4 +- gunicorn.conf.py | 2 +- instances/migrations/0001_initial.py | 19 +- .../migrations/0002_instance_is_template.py | 19 - instances/migrations/0003_instance_created.py | 21 - .../migrations/0004_auto_20180724_1136.py | 20 - instances/models.py | 14 +- instances/templates/edit_instance_volume.html | 3 +- instances/templates/instance.html | 78 +- instances/urls.py | 20 +- instances/views.py | 60 +- logs/migrations/0001_initial.py | 19 +- logs/migrations/0002_auto_20150316_1420.py | 28 - logs/migrations/0003_auto_20150518_1855.py | 24 - logs/models.py | 12 +- logs/templates/paging.html | 4 +- logs/urls.py | 8 +- networks/forms.py | 2 +- networks/templates/network.html | 2 + networks/views.py | 20 +- nwfilters/templates/nwfilter.html | 10 +- nwfilters/views.py | 4 +- secrets/views.py | 2 +- static/js/bootstrap-multiselect.js | 4 +- static/js/novnc/app/styles/base.css | 2 +- .../dist/babel-worker.js | 1540 +++++----- .../src/browser-es-module-loader.js | 10 +- .../js/novnc/vendor/pako/lib/utils/common.js | 2 +- .../js/novnc/vendor/pako/lib/zlib/inffast.js | 6 +- static/js/plugins/flot/excanvas.min.js | 1 - static/js/plugins/flot/flot-data.js | 1244 -------- static/js/plugins/flot/jquery.flot.js | 2599 ----------------- static/js/plugins/flot/jquery.flot.pie.js | 750 ----- static/js/plugins/flot/jquery.flot.resize.js | 60 - .../plugins/flot/jquery.flot.tooltip.min.js | 12 - static/js/spice-html5/spice.css | 5 +- storages/views.py | 14 +- vrtManager/connection.py | 42 +- vrtManager/create.py | 11 +- vrtManager/hostdetails.py | 10 +- vrtManager/instance.py | 84 +- vrtManager/network.py | 12 +- vrtManager/nwfilters.py | 14 +- vrtManager/storage.py | 6 +- vrtManager/util.py | 12 +- webvirtcloud/settings.py.template | 133 +- webvirtcloud/urls.py | 18 +- webvirtcloud/wsgi.py | 4 +- webvirtcloud/wsgi_custom.py | 17 +- 98 files changed, 1525 insertions(+), 6658 deletions(-) delete mode 100644 accounts/migrations/0002_auto_20150325_0846.py delete mode 100644 accounts/migrations/0003_usersshkey.py delete mode 100644 accounts/migrations/0004_userattributes.py delete mode 100644 accounts/migrations/0004_userinstance_is_vnc.py delete mode 100644 accounts/migrations/0005_userattributes_can_clone_instances.py delete mode 100644 accounts/migrations/0006_userattributes_max_disk_size.py delete mode 100644 accounts/migrations/0007_auto_20160426_0635.py delete mode 100644 accounts/migrations/0008_merge.py delete mode 100644 accounts/migrations/0009_auto_20171026_0805.py delete mode 100644 accounts/migrations/0010_auto_20180625_1236.py delete mode 100644 accounts/migrations/0011_auto_20180625_1313.py delete mode 100644 accounts/migrations/0012_auto_20180625_1331.py delete mode 100644 accounts/migrations/0013_auto_20180625_1358.py delete mode 100644 accounts/migrations/0014_auto_20180808_1436.py delete mode 100644 accounts/migrations/0015_auto_20180808_1449.py delete mode 100644 computes/migrations/0002_compute_details.py delete mode 100644 computes/migrations/0003_auto_20200121_1523.py rename create/migrations/{0002_auto_20150325_0921.py => 0002_addFlavors.py} (92%) delete mode 100644 instances/migrations/0002_instance_is_template.py delete mode 100644 instances/migrations/0003_instance_created.py delete mode 100644 instances/migrations/0004_auto_20180724_1136.py delete mode 100644 logs/migrations/0002_auto_20150316_1420.py delete mode 100644 logs/migrations/0003_auto_20150518_1855.py delete mode 100755 static/js/plugins/flot/excanvas.min.js delete mode 100755 static/js/plugins/flot/flot-data.js delete mode 100755 static/js/plugins/flot/jquery.flot.js delete mode 100755 static/js/plugins/flot/jquery.flot.pie.js delete mode 100755 static/js/plugins/flot/jquery.flot.resize.js delete mode 100755 static/js/plugins/flot/jquery.flot.tooltip.min.js diff --git a/.gitignore b/.gitignore index 65d6949..289210e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .vagrant venv +venv2 .vscode .idea .DS_* diff --git a/.travis.yml b/.travis.yml index 747a498..e012921 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ language: python python: - - "2.7" + - "3.6" env: - - DJANGO=1.11.26 + - DJANGO=2.2.10 install: - pip install -r dev/requirements.txt script: diff --git a/Dockerfile b/Dockerfile index 0c04c68..c3b122f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,21 +6,21 @@ RUN echo 'APT::Get::Clean=always;' >> /etc/apt/apt.conf.d/99AutomaticClean RUN apt-get update -qqy RUN DEBIAN_FRONTEND=noninteractive apt-get -qyy install \ -o APT::Install-Suggests=false \ - git python-virtualenv python-dev python-lxml libvirt-dev zlib1g-dev nginx libsasl2-modules + git python3-virtualenv python3-dev python3-lxml virtualenv libvirt-dev zlib1g-dev nginx libsasl2-modules ADD . /srv/webvirtcloud RUN chown -R www-data:www-data /srv/webvirtcloud # Setup webvirtcloud RUN cd /srv/webvirtcloud && \ - virtualenv venv && \ + virtualenv --python=python3 venv && \ . venv/bin/activate && \ - pip install -U pip && \ - pip install -r conf/requirements.txt && \ + pip3 install -U pip && \ + pip3 install -r conf/requirements.txt && \ chown -R www-data:www-data /srv/webvirtcloud RUN cd /srv/webvirtcloud && . venv/bin/activate && \ - python manage.py migrate && \ + python3 manage.py migrate && \ chown -R www-data:www-data /srv/webvirtcloud # Setup Nginx diff --git a/README.md b/README.md index 6d810b5..1b2fcb2 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ ## WebVirtCloud - +###### Python3 & Django 2.11 ## Features * QEMU/KVM Hypervisor Management @@ -38,10 +38,10 @@ haystack = string.ascii_letters + string.digits + string.punctuation print(''.join([random.SystemRandom().choice(haystack) for _ in range(50)])) ``` -### Install WebVirtCloud panel (Ubuntu) +### Install WebVirtCloud panel (Ubuntu 18.04+ LTS) ```bash -sudo apt-get -y install git virtualenv python-virtualenv python-dev python-lxml libvirt-dev zlib1g-dev libxslt1-dev nginx supervisor libsasl2-modules gcc pkg-config python-guestfs +sudo apt-get -y install git virtualenv python3-virtualenv python3-dev python3-lxml libvirt-dev zlib1g-dev libxslt1-dev nginx supervisor libsasl2-modules gcc pkg-config python3-guestfs git clone https://github.com/retspen/webvirtcloud cd webvirtcloud cp webvirtcloud/settings.py.template webvirtcloud/settings.py @@ -52,7 +52,7 @@ cd .. sudo mv webvirtcloud /srv sudo chown -R www-data:www-data /srv/webvirtcloud cd /srv/webvirtcloud -virtualenv venv +virtualenv -p python3 venv source venv/bin/activate pip install -r conf/requirements.txt python manage.py migrate @@ -76,11 +76,11 @@ Done!! Go to http://serverip and you should see the login screen. - -### Install WebVirtCloud panel (CentOS) +### Install WebVirtCloud panel (CentOS8/OEL8) ```bash -sudo yum -y install python-virtualenv python-devel libvirt-devel glibc gcc nginx supervisor python-lxml git python-libguestfs iproute-tc +sudo yum -y install epel-release +sudo yum -y install python3-virtualenv python3-devel libvirt-devel glibc gcc nginx supervisor python3-lxml git python3-libguestfs iproute-tc cyrus-sasl-md5 python3-libguestfs ``` #### Creating directories and cloning repo @@ -90,15 +90,17 @@ sudo mkdir /srv && cd /srv sudo git clone https://github.com/retspen/webvirtcloud && cd webvirtcloud cp webvirtcloud/settings.py.template webvirtcloud/settings.py # now put secret key to webvirtcloud/settings.py +# create secret key manually or use that command +sudo sed -r "s/SECRET_KEY = ''/SECRET_KEY = '"`python3 /srv/webvirtcloud/conf/runit/secret_generator.py`"'/" -i /srv/webvirtcloud/webvirtcloud/settings.py ``` #### Start installation webvirtcloud ``` -sudo virtualenv venv -sudo source venv/bin/activate -sudo venv/bin/pip install -r conf/requirements.txt -sudo cp conf/nginx/webvirtcloud.conf /etc/nginx/conf.d/ -sudo venv/bin/python manage.py migrate +virtualenv-3 venv +source venv/bin/activate +pip3 install -r conf/requirements.txt +cp conf/nginx/webvirtcloud.conf /etc/nginx/conf.d/ +python3 manage.py migrate ``` #### Configure the supervisor for CentOS @@ -115,7 +117,7 @@ autorestart=true redirect_stderr=true [program:novncd] -command=/srv/webvirtcloud/venv/bin/python /srv/webvirtcloud/console/novncd +command=/srv/webvirtcloud/venv/bin/python3 /srv/webvirtcloud/console/novncd directory=/srv/webvirtcloud user=nginx autostart=true @@ -191,11 +193,20 @@ Change permission for selinux: ```bash sudo semanage fcontext -a -t httpd_sys_content_t "/srv/webvirtcloud(/.*)" +sudo setsebool -P httpd_can_network_connect on -P ``` -Add required user to the kvm group: +Add required user to the kvm group(if you not install with root): ```bash -sudo usermod -G kvm -a webvirtmgr +sudo usermod -G kvm -a +``` + +Allow http ports on firewall: +```bash +sudo firewall-cmd --add-service=http +sudo firewall-cmd --add-service=http --permanent +sudo firewall-cmd --add-port=6080/tcp +sudo firewall-cmd --add-port=6080/tcp --permanent ``` Let's restart nginx and the supervisord services: @@ -226,7 +237,7 @@ Done!! Go to http://serverip and you should see the login screen. -### Alternative running novncd via runit +### Alternative running novncd via runit(Debian) Alternative to running nonvcd via supervisor is runit. On Debian systems install runit and configure novncd service @@ -272,11 +283,12 @@ datasource: ### How To Update ```bash -cd -sudo source venv/bin/activate +# Go to Installation Directory +cd /srv/webvirtcloud +source venv/bin/activate git pull -pip install -U -r conf/requirements.txt -python manage.py migrate +pip3 install -U -r conf/requirements.txt +python3 manage.py migrate sudo service supervisor restart ``` ### Screenshots diff --git a/Vagrantfile b/Vagrantfile index 21819f3..d92377c 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -12,10 +12,10 @@ Vagrant.configure(2) do |config| sudo sed -i 's/auth_tcp = \"sasl\"/auth_tcp = \"none\"/g' /etc/libvirt/libvirtd.conf sudo service libvirt-bin restart sudo adduser vagrant libvirtd - sudo apt-get -y install python-virtualenv python-dev python-lxml libvirt-dev zlib1g-dev - virtualenv /vagrant/venv + sudo apt-get -y install python3-virtualenv virtualenv python3-pip python3-dev python3-lxml libvirt-dev zlib1g-dev python3-guestfs + virtualenv -p python3 /vagrant/venv source /vagrant/venv/bin/activate - pip install -r /vagrant/dev/requirements.txt + pip3 install -r /vagrant/dev/requirements.txt SHELL end # To start this machine run "vagrant up prod" @@ -24,6 +24,7 @@ Vagrant.configure(2) do |config| prod.vm.box = "ubuntu/bionic64" prod.vm.hostname = "webvirtcloud" prod.vm.network "private_network", ip: "192.168.33.11" + prod.vm.network "forwarded_port", guest: 80, host: 8081 #prod.vm.synced_folder ".", "/srv/webvirtcloud" prod.vm.provision "shell", inline: <<-SHELL sudo mkdir /srv/webvirtcloud @@ -33,15 +34,15 @@ Vagrant.configure(2) do |config| sudo service libvirt-bin restart sudo adduser vagrant libvirtd sudo chown -R vagrant:vagrant /srv/webvirtcloud - sudo apt-get -y install python-virtualenv python-dev python-lxml python-pip libvirt-dev zlib1g-dev libxslt1-dev nginx supervisor libsasl2-modules gcc pkg-config python-guestfs - virtualenv /srv/webvirtcloud/venv + sudo apt-get -y install python3-virtualenv python3-dev python3-lxml python3-pip virtualenv libvirt-dev zlib1g-dev libxslt1-dev nginx supervisor libsasl2-modules gcc pkg-config python3-guestfs + virtualenv -p python3 /srv/webvirtcloud/venv source /srv/webvirtcloud/venv/bin/activate - pip install -r /srv/webvirtcloud/dev/requirements.txt + pip3 install -r /srv/webvirtcloud/requirements.txt sudo cp /srv/webvirtcloud/conf/supervisor/webvirtcloud.conf /etc/supervisor/conf.d sudo cp /srv/webvirtcloud/conf/nginx/webvirtcloud.conf /etc/nginx/conf.d sudo cp /srv/webvirtcloud/webvirtcloud/settings.py.template /srv/webvirtcloud/webvirtcloud/settings.py - sudo sed "s/SECRET_KEY = ''/SECRET_KEY = '"`python /srv/webvirtcloud/conf/runit/secret_generator.py`"'/" -i /srv/webvirtcloud/webvirtcloud/settings.py - python /srv/webvirtcloud/manage.py migrate + sudo sed "s/SECRET_KEY = ''/SECRET_KEY = '"`python3 /srv/webvirtcloud/conf/runit/secret_generator.py`"'/" -i /srv/webvirtcloud/webvirtcloud/settings.py + python3 /srv/webvirtcloud/manage.py migrate sudo rm /etc/nginx/sites-enabled/default sudo chown -R www-data:www-data /srv/webvirtcloud sudo service nginx restart diff --git a/accounts/forms.py b/accounts/forms.py index 4127ac4..db53ed5 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -9,7 +9,8 @@ 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=not settings.ALLOW_EMPTY_PASSWORD, 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'] diff --git a/accounts/migrations/0001_initial.py b/accounts/migrations/0001_initial.py index 3989532..1990eeb 100644 --- a/accounts/migrations/0001_initial.py +++ b/accounts/migrations/0001_initial.py @@ -1,29 +1,51 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals +# Generated by Django 2.2.10 on 2020-01-28 07:01 -from django.db import models, migrations from django.conf import settings +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion class Migration(migrations.Migration): + initial = True + dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), ('instances', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] operations = [ + migrations.CreateModel( + name='UserSSHKey', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('keyname', models.CharField(max_length=25)), + ('keypublic', models.CharField(max_length=500)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to=settings.AUTH_USER_MODEL)), + ], + ), migrations.CreateModel( name='UserInstance', fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('is_change', models.BooleanField(default=False)), ('is_delete', models.BooleanField(default=False)), - ('instance', models.ForeignKey(to='instances.Instance')), - ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)), + ('is_vnc', models.BooleanField(default=False)), + ('instance', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='instances.Instance')), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='UserAttributes', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('can_clone_instances', models.BooleanField(default=True)), + ('max_instances', models.IntegerField(default=1, help_text='-1 for unlimited. Any integer value', validators=[django.core.validators.MinValueValidator(-1)])), + ('max_cpus', models.IntegerField(default=1, help_text='-1 for unlimited. Any integer value', validators=[django.core.validators.MinValueValidator(-1)])), + ('max_memory', models.IntegerField(default=2048, help_text='-1 for unlimited. Any integer value', validators=[django.core.validators.MinValueValidator(-1)])), + ('max_disk_size', models.IntegerField(default=20, help_text='-1 for unlimited. Any integer value', validators=[django.core.validators.MinValueValidator(-1)])), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], - options={ - }, - bases=(models.Model,), ), ] diff --git a/accounts/migrations/0002_auto_20150325_0846.py b/accounts/migrations/0002_auto_20150325_0846.py deleted file mode 100644 index 8780f97..0000000 --- a/accounts/migrations/0002_auto_20150325_0846.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import migrations - - -def add_useradmin(apps, schema_editor): - from django.utils import timezone - from django.contrib.auth.models import User - - User.objects.create_superuser('admin', None, 'admin', - last_login=timezone.now() - ) - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0001_initial'), - ] - - operations = [ - migrations.RunPython(add_useradmin), - ] diff --git a/accounts/migrations/0003_usersshkey.py b/accounts/migrations/0003_usersshkey.py deleted file mode 100644 index b00bc62..0000000 --- a/accounts/migrations/0003_usersshkey.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- 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', '0002_auto_20150325_0846'), - ] - - operations = [ - migrations.CreateModel( - name='UserSSHKey', - fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('keyname', models.CharField(max_length=25)), - ('keypublic', models.CharField(max_length=500)), - ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)), - ], - ), - ] diff --git a/accounts/migrations/0004_userattributes.py b/accounts/migrations/0004_userattributes.py deleted file mode 100644 index fb32539..0000000 --- a/accounts/migrations/0004_userattributes.py +++ /dev/null @@ -1,26 +0,0 @@ -# -*- 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)), - ], - ), - ] diff --git a/accounts/migrations/0004_userinstance_is_vnc.py b/accounts/migrations/0004_userinstance_is_vnc.py deleted file mode 100644 index 9c1c9b8..0000000 --- a/accounts/migrations/0004_userinstance_is_vnc.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0003_usersshkey'), - ] - - operations = [ - migrations.AddField( - model_name='userinstance', - name='is_vnc', - field=models.BooleanField(default=False), - ), - ] diff --git a/accounts/migrations/0005_userattributes_can_clone_instances.py b/accounts/migrations/0005_userattributes_can_clone_instances.py deleted file mode 100644 index 4539657..0000000 --- a/accounts/migrations/0005_userattributes_can_clone_instances.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- 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), - ), - ] diff --git a/accounts/migrations/0006_userattributes_max_disk_size.py b/accounts/migrations/0006_userattributes_max_disk_size.py deleted file mode 100644 index 3d21f5f..0000000 --- a/accounts/migrations/0006_userattributes_max_disk_size.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- 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), - ), - ] diff --git a/accounts/migrations/0007_auto_20160426_0635.py b/accounts/migrations/0007_auto_20160426_0635.py deleted file mode 100644 index 2f92aba..0000000 --- a/accounts/migrations/0007_auto_20160426_0635.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- 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), - ), - ] diff --git a/accounts/migrations/0008_merge.py b/accounts/migrations/0008_merge.py deleted file mode 100644 index 8edf672..0000000 --- a/accounts/migrations/0008_merge.py +++ /dev/null @@ -1,15 +0,0 @@ -# -*- 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 = [ - ] diff --git a/accounts/migrations/0009_auto_20171026_0805.py b/accounts/migrations/0009_auto_20171026_0805.py deleted file mode 100644 index 7d035c7..0000000 --- a/accounts/migrations/0009_auto_20171026_0805.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0008_merge'), - ] - - operations = [ - migrations.AlterField( - model_name='userattributes', - name='can_clone_instances', - field=models.BooleanField(default=True), - ), - ] diff --git a/accounts/migrations/0010_auto_20180625_1236.py b/accounts/migrations/0010_auto_20180625_1236.py deleted file mode 100644 index 23e1548..0000000 --- a/accounts/migrations/0010_auto_20180625_1236.py +++ /dev/null @@ -1,35 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.11.13 on 2018-06-25 12:36 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0009_auto_20171026_0805'), - ] - - operations = [ - migrations.AlterField( - model_name='userattributes', - name='max_cpus', - field=models.IntegerField(default=1, help_text=b'-1 for unlimited. Any integer value'), - ), - migrations.AlterField( - model_name='userattributes', - name='max_disk_size', - field=models.IntegerField(default=20, help_text=b'-1 for unlimited. Any integer value'), - ), - migrations.AlterField( - model_name='userattributes', - name='max_instances', - field=models.IntegerField(default=1, help_text=b'-1 for unlimited. Any integer value'), - ), - migrations.AlterField( - model_name='userattributes', - name='max_memory', - field=models.IntegerField(default=2048, help_text=b'-1 for unlimited. Any integer value'), - ), - ] diff --git a/accounts/migrations/0011_auto_20180625_1313.py b/accounts/migrations/0011_auto_20180625_1313.py deleted file mode 100644 index 1ee194b..0000000 --- a/accounts/migrations/0011_auto_20180625_1313.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.11.13 on 2018-06-25 13:13 -from __future__ import unicode_literals - -import django.core.validators -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0010_auto_20180625_1236'), - ] - - operations = [ - migrations.AlterField( - model_name='userattributes', - name='max_cpus', - field=models.IntegerField(default=1, help_text=b'-1 for unlimited. Any integer value', validators=[django.core.validators.MinValueValidator(-1)]), - ), - migrations.AlterField( - model_name='userattributes', - name='max_disk_size', - field=models.IntegerField(default=20, help_text=b'-1 for unlimited. Any integer value', validators=[django.core.validators.MinValueValidator(-1)]), - ), - migrations.AlterField( - model_name='userattributes', - name='max_instances', - field=models.IntegerField(default=1, help_text=b'-1 for unlimited. Any integer value', validators=[django.core.validators.MinValueValidator(-1)]), - ), - migrations.AlterField( - model_name='userattributes', - name='max_memory', - field=models.IntegerField(default=2048, help_text=b'-1 for unlimited. Any integer value', validators=[django.core.validators.MinValueValidator(-1)]), - ), - ] diff --git a/accounts/migrations/0012_auto_20180625_1331.py b/accounts/migrations/0012_auto_20180625_1331.py deleted file mode 100644 index 827599e..0000000 --- a/accounts/migrations/0012_auto_20180625_1331.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.11.13 on 2018-06-25 13:31 -from __future__ import unicode_literals - -import django.core.validators -from django.db import migrations, models -import re - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0011_auto_20180625_1313'), - ] - - operations = [ - migrations.AlterField( - model_name='userattributes', - name='max_cpus', - field=models.IntegerField(default=1, help_text=b'-1 for unlimited. Any integer value', validators=[django.core.validators.RegexValidator(re.compile('^-?\\d+\\Z'), code='invalid', message='Enter a valid integer.')]), - ), - migrations.AlterField( - model_name='userattributes', - name='max_disk_size', - field=models.IntegerField(default=20, help_text=b'-1 for unlimited. Any integer value', validators=[django.core.validators.RegexValidator(re.compile('^-?\\d+\\Z'), code='invalid', message='Enter a valid integer.')]), - ), - migrations.AlterField( - model_name='userattributes', - name='max_instances', - field=models.IntegerField(default=1, help_text=b'-1 for unlimited. Any integer value', validators=[django.core.validators.RegexValidator(re.compile('^-?\\d+\\Z'), code='invalid', message='Enter a valid integer.')]), - ), - migrations.AlterField( - model_name='userattributes', - name='max_memory', - field=models.IntegerField(default=2048, help_text=b'-1 for unlimited. Any integer value', validators=[django.core.validators.RegexValidator(re.compile('^-?\\d+\\Z'), code='invalid', message='Enter a valid integer.')]), - ), - ] diff --git a/accounts/migrations/0013_auto_20180625_1358.py b/accounts/migrations/0013_auto_20180625_1358.py deleted file mode 100644 index 1fdec50..0000000 --- a/accounts/migrations/0013_auto_20180625_1358.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.11.13 on 2018-06-25 13:58 -from __future__ import unicode_literals - -import django.core.validators -from django.db import migrations, models -import re - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0012_auto_20180625_1331'), - ] - - operations = [ - migrations.AlterField( - model_name='userattributes', - name='max_cpus', - field=models.IntegerField(default=1, help_text=b'-1 for unlimited. Any integer value', validators=[django.core.validators.RegexValidator(re.compile('^-?\\d+\\Z'), code='invalid', message='Enter a valid integer.'), django.core.validators.MinValueValidator(-1)]), - ), - migrations.AlterField( - model_name='userattributes', - name='max_disk_size', - field=models.IntegerField(default=20, help_text=b'-1 for unlimited. Any integer value', validators=[django.core.validators.RegexValidator(re.compile('^-?\\d+\\Z'), code='invalid', message='Enter a valid integer.'), django.core.validators.MinValueValidator(-1)]), - ), - migrations.AlterField( - model_name='userattributes', - name='max_instances', - field=models.IntegerField(default=1, help_text=b'-1 for unlimited. Any integer value', validators=[django.core.validators.RegexValidator(re.compile('^-?\\d+\\Z'), code='invalid', message='Enter a valid integer.'), django.core.validators.MinValueValidator(-1)]), - ), - migrations.AlterField( - model_name='userattributes', - name='max_memory', - field=models.IntegerField(default=2048, help_text=b'-1 for unlimited. Any integer value', validators=[django.core.validators.RegexValidator(re.compile('^-?\\d+\\Z'), code='invalid', message='Enter a valid integer.'), django.core.validators.MinValueValidator(-1)]), - ), - ] diff --git a/accounts/migrations/0014_auto_20180808_1436.py b/accounts/migrations/0014_auto_20180808_1436.py deleted file mode 100644 index a4f3c78..0000000 --- a/accounts/migrations/0014_auto_20180808_1436.py +++ /dev/null @@ -1,36 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.11.13 on 2018-08-08 11:36 -from __future__ import unicode_literals - -import django.core.validators -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0013_auto_20180625_1358'), - ] - - operations = [ - migrations.AlterField( - model_name='userattributes', - name='max_cpus', - field=models.IntegerField(default=1, help_text=b'-1 for unlimited. Any integer value', validators=[django.core.validators.MinValueValidator(-1)]), - ), - migrations.AlterField( - model_name='userattributes', - name='max_disk_size', - field=models.IntegerField(default=20, help_text=b'-1 for unlimited. Any integer value', validators=[django.core.validators.MinValueValidator(-1)]), - ), - migrations.AlterField( - model_name='userattributes', - name='max_instances', - field=models.IntegerField(default=1, help_text=b'-1 for unlimited. Any integer value', validators=[django.core.validators.MinValueValidator(-1)]), - ), - migrations.AlterField( - model_name='userattributes', - name='max_memory', - field=models.IntegerField(default=2048, help_text=b'-1 for unlimited. Any integer value', validators=[django.core.validators.MinValueValidator(-1)]), - ), - ] diff --git a/accounts/migrations/0015_auto_20180808_1449.py b/accounts/migrations/0015_auto_20180808_1449.py deleted file mode 100644 index d94905a..0000000 --- a/accounts/migrations/0015_auto_20180808_1449.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.11.13 on 2018-08-08 11:49 -from __future__ import unicode_literals - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('accounts', '0014_auto_20180808_1436'), - ] - - operations = [ - migrations.AlterField( - model_name='usersshkey', - name='user', - field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to=settings.AUTH_USER_MODEL), - ), - ] diff --git a/accounts/models.py b/accounts/models.py index 42c8051..77cf81a 100644 --- a/accounts/models.py +++ b/accounts/models.py @@ -1,36 +1,39 @@ -from django.db import models +from django.db.models import Model, BooleanField, IntegerField, CharField +from django.db.models import ForeignKey, OneToOneField +from django.db.models import CASCADE, DO_NOTHING from django.contrib.auth.models import User from django.conf import settings from instances.models import Instance from django.core.validators import MinValueValidator -class UserInstance(models.Model): - user = models.ForeignKey(User, on_delete=models.CASCADE) - instance = models.ForeignKey(Instance, on_delete=models.CASCADE) - is_change = models.BooleanField(default=False) - is_delete = models.BooleanField(default=False) - is_vnc = models.BooleanField(default=False) +class UserInstance(Model): + user = ForeignKey(User, on_delete=CASCADE) + instance = ForeignKey(Instance, on_delete=CASCADE) + is_change = BooleanField(default=False) + is_delete = BooleanField(default=False) + is_vnc = BooleanField(default=False) def __unicode__(self): return self.instance.name -class UserSSHKey(models.Model): - user = models.ForeignKey(User, on_delete=models.DO_NOTHING) - keyname = models.CharField(max_length=25) - keypublic = models.CharField(max_length=500) +class UserSSHKey(Model): + user = ForeignKey(User, on_delete=DO_NOTHING) + keyname = CharField(max_length=25) + keypublic = CharField(max_length=500) def __unicode__(self): return self.keyname -class UserAttributes(models.Model): - user = models.OneToOneField(User, on_delete=models.CASCADE) - can_clone_instances = models.BooleanField(default=True) - max_instances = models.IntegerField(default=1, help_text="-1 for unlimited. Any integer value", validators=[MinValueValidator(-1),]) - max_cpus = models.IntegerField(default=1, help_text="-1 for unlimited. Any integer value", validators=[MinValueValidator(-1)]) - max_memory = models.IntegerField(default=2048, help_text="-1 for unlimited. Any integer value", validators=[MinValueValidator(-1)]) - max_disk_size = models.IntegerField(default=20, help_text="-1 for unlimited. Any integer value", validators=[MinValueValidator(-1)]) + +class UserAttributes(Model): + user = OneToOneField(User, on_delete=CASCADE) + can_clone_instances = BooleanField(default=True) + max_instances = IntegerField(default=1, help_text="-1 for unlimited. Any integer value", validators=[MinValueValidator(-1), ]) + max_cpus = IntegerField(default=1, help_text="-1 for unlimited. Any integer value", validators=[MinValueValidator(-1)]) + max_memory = IntegerField(default=2048, help_text="-1 for unlimited. Any integer value", validators=[MinValueValidator(-1)]) + max_disk_size = IntegerField(default=20, help_text="-1 for unlimited. Any integer value", validators=[MinValueValidator(-1)]) @staticmethod def create_missing_userattributes(user): diff --git a/accounts/templates/account.html b/accounts/templates/account.html index 56f91b8..0f9bbb7 100644 --- a/accounts/templates/account.html +++ b/accounts/templates/account.html @@ -87,8 +87,8 @@
- +
@@ -96,8 +96,8 @@
- +
@@ -105,8 +105,8 @@
- +
@@ -124,7 +124,7 @@
{% csrf_token %} -
diff --git a/accounts/urls.py b/accounts/urls.py index c0ea4f1..6b49b70 100644 --- a/accounts/urls.py +++ b/accounts/urls.py @@ -1,10 +1,10 @@ -from django.conf.urls import url +from django.urls import path, re_path from django.contrib.auth import views as auth_views from . import views urlpatterns = [ - url(r'^login/$', auth_views.LoginView.as_view(template_name='login.html'), name='login'), - url(r'^logout/$', auth_views.LogoutView.as_view(template_name='logout.html'), name='logout'), - url(r'^profile/$', views.profile, name='profile'), url(r'^$', views.accounts, name='accounts'), - url(r'^profile/(?P[0-9]+)/$', views.account, name='account'), + path('login/', auth_views.LoginView.as_view(template_name='login.html'), name='login'), + path('logout/', auth_views.LogoutView.as_view(template_name='logout.html'), name='logout'), + path('profile/', views.profile, name='profile'), path('', views.accounts, name='accounts'), + re_path(r'^profile/(?P[0-9]+)/$', views.account, name='account'), ] diff --git a/computes/forms.py b/computes/forms.py index 5389708..bbde4d4 100644 --- a/computes/forms.py +++ b/computes/forms.py @@ -151,10 +151,8 @@ class ComputeEditHostForm(forms.Form): class ComputeAddSocketForm(forms.Form): - name = forms.CharField(error_messages={'required': _('No hostname has been entered')}, - max_length=64) - details = forms.CharField(error_messages={'required': _('No details has been entred')}, - max_length=50) + name = forms.CharField(error_messages={'required': _('No hostname has been entered')}, max_length=64) + details = forms.CharField(error_messages={'required': _('No details has been entred')}, max_length=50) def clean_name(self): name = self.cleaned_data['name'] diff --git a/computes/migrations/0001_initial.py b/computes/migrations/0001_initial.py index e8d6139..c8f9183 100644 --- a/computes/migrations/0001_initial.py +++ b/computes/migrations/0001_initial.py @@ -1,11 +1,12 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals +# Generated by Django 2.2.10 on 2020-01-28 07:01 -from django.db import models, migrations +from django.db import migrations, models class Migration(migrations.Migration): + initial = True + dependencies = [ ] @@ -13,15 +14,13 @@ class Migration(migrations.Migration): migrations.CreateModel( name='Compute', fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(max_length=20)), - ('hostname', models.CharField(max_length=20)), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=64)), + ('hostname', models.CharField(max_length=64)), ('login', models.CharField(max_length=20)), - ('password', models.CharField(max_length=14, null=True, blank=True)), + ('password', models.CharField(blank=True, max_length=14, null=True)), + ('details', models.CharField(blank=True, max_length=64, null=True)), ('type', models.IntegerField()), ], - options={ - }, - bases=(models.Model,), ), ] diff --git a/computes/migrations/0002_compute_details.py b/computes/migrations/0002_compute_details.py deleted file mode 100644 index 1e0fdf5..0000000 --- a/computes/migrations/0002_compute_details.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import models, migrations - -class Migration(migrations.Migration): - - dependencies = [ - ('computes', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='Compute', - name='details', - field=models.CharField(max_length=50, null=True, blank=True), - ), - ] diff --git a/computes/migrations/0003_auto_20200121_1523.py b/computes/migrations/0003_auto_20200121_1523.py deleted file mode 100644 index 361cbc1..0000000 --- a/computes/migrations/0003_auto_20200121_1523.py +++ /dev/null @@ -1,30 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.11.26 on 2020-01-21 12:23 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('computes', '0002_compute_details'), - ] - - operations = [ - migrations.AlterField( - model_name='compute', - name='details', - field=models.CharField(blank=True, max_length=64, null=True), - ), - migrations.AlterField( - model_name='compute', - name='hostname', - field=models.CharField(max_length=64), - ), - migrations.AlterField( - model_name='compute', - name='name', - field=models.CharField(max_length=64), - ), - ] diff --git a/computes/models.py b/computes/models.py index 1a83e59..db224a3 100644 --- a/computes/models.py +++ b/computes/models.py @@ -1,13 +1,13 @@ -from django.db import models +from django.db.models import Model, CharField, IntegerField -class Compute(models.Model): - name = models.CharField(max_length=64) - hostname = models.CharField(max_length=64) - login = models.CharField(max_length=20) - password = models.CharField(max_length=14, blank=True, null=True) - details = models.CharField(max_length=64, null=True, blank=True) - type = models.IntegerField() +class Compute(Model): + name = CharField(max_length=64) + hostname = CharField(max_length=64) + login = CharField(max_length=20) + password = CharField(max_length=14, blank=True, null=True) + details = CharField(max_length=64, null=True, blank=True) + type = IntegerField() def __unicode__(self): return self.hostname diff --git a/computes/urls.py b/computes/urls.py index 350fc00..be5f09b 100644 --- a/computes/urls.py +++ b/computes/urls.py @@ -1,4 +1,4 @@ -from django.conf.urls import url +from django.urls import path, re_path from storages.views import storages, storage, get_volumes from networks.views import networks, network from secrets.views import secrets @@ -9,23 +9,24 @@ from instances.views import instances from nwfilters.views import nwfilter, nwfilters urlpatterns = [ - url(r'^$', computes, name='computes'), - url(r'^(?P[0-9]+)/$', overview, name='overview'), - url(r'^(?P[0-9]+)/statistics$', compute_graph, name='compute_graph'), - url(r'^(?P[0-9]+)/instances/$', instances, name='instances'), - url(r'^(?P[0-9]+)/storages/$', storages, name='storages'), - url(r'^(?P[0-9]+)/storage/(?P[\w\-\.\/]+)/volumes$', get_volumes, name='volumes'), - url(r'^(?P[0-9]+)/storage/(?P[\w\-\.\/]+)/$', storage, name='storage'), - url(r'^(?P[0-9]+)/networks/$', networks, name='networks'), - url(r'^(?P[0-9]+)/network/(?P[\w\-\.]+)/$', network, name='network'), - url(r'^(?P[0-9]+)/interfaces/$', interfaces, name='interfaces'), - url(r'^(?P[0-9]+)/interface/(?P[\w\-\.\:]+)/$', interface, name='interface'), - url(r'^(?P[0-9]+)/nwfilters/$', nwfilters, name='nwfilters'), - url(r'^(?P[0-9]+)/nwfilter/(?P[\w\-\.\:]+)/$', nwfilter, name='nwfilter'), - url(r'^(?P[0-9]+)/secrets/$', secrets, name='secrets'), - url(r'^(?P[0-9]+)/create/$', create_instance_select_type, name='create_instance_select_type'), - url(r'^(?P[0-9]+)/create/archs/(?P[\w\-\.\/]+)/machines/(?P[\w\-\.\/]+)$', create_instance, name='create_instance'), - url(r'^(?P[0-9]+)/archs/(?P[\w\-\.\/]+)/machines$', get_compute_machine_types, name='machines'), - url(r'^(?P[0-9]+)/archs/(?P[\w\-\.\/]+)/machines/(?P[\w\-\.\/]+)/disks/(?P[\w\-\.\/]+)/buses$', get_compute_disk_buses, name='buses'), - url(r'^(?P[0-9]+)/archs/(?P[\w\-\.\/]+)/machines/(?P[\w\-\.\/]+)/capabilities$', get_dom_capabilities, name='domcaps'), + path('', computes, name='computes'), + re_path(r'^(?P[0-9]+)/$', overview, name='overview'), + re_path(r'^(?P[0-9]+)/statistics$', compute_graph, name='compute_graph'), + re_path(r'^(?P[0-9]+)/instances/$', instances, name='instances'), + re_path(r'^(?P[0-9]+)/storages/$', storages, name='storages'), + re_path(r'^(?P[0-9]+)/storage/(?P[\w\-\.\/]+)/volumes$', get_volumes, name='volumes'), + re_path(r'^(?P[0-9]+)/storage/(?P[\w\-\.\/]+)/$', storage, name='storage'), + re_path(r'^(?P[0-9]+)/networks/$', networks, name='networks'), + re_path(r'^(?P[0-9]+)/network/(?P[\w\-\.]+)/$', network, name='network'), + re_path(r'^(?P[0-9]+)/interfaces/$', interfaces, name='interfaces'), + re_path(r'^(?P[0-9]+)/interface/(?P[\w\-\.\:]+)/$', interface, name='interface'), + re_path(r'^(?P[0-9]+)/nwfilters/$', nwfilters, name='nwfilters'), + re_path(r'^(?P[0-9]+)/nwfilter/(?P[\w\-\.\:]+)/$', nwfilter, name='nwfilter'), + re_path(r'^(?P[0-9]+)/secrets/$', secrets, name='secrets'), + re_path(r'^(?P[0-9]+)/create/$', create_instance_select_type, name='create_instance_select_type'), + re_path(r'^(?P[0-9]+)/create/archs/(?P[\w\-\.\/]+)/machines/(?P[\w\-\.\/]+)$', create_instance, name='create_instance'), + re_path(r'^(?P[0-9]+)/archs/(?P[\w\-\.\/]+)/machines$', get_compute_machine_types, name='machines'), + re_path(r'^(?P[0-9]+)/archs/(?P[\w\-\.\/]+)/machines/(?P[\w\-\.\/]+)/disks/(?P[\w\-\.\/]+)/buses$', get_compute_disk_buses, name='buses'), + re_path(r'^(?P[0-9]+)/archs/(?P[\w\-\.\/]+)/machines/(?P[\w\-\.\/]+)/capabilities$', get_dom_capabilities, name='domcaps'), ] + diff --git a/conf/daemon/gstfsd b/conf/daemon/gstfsd index 1851770..589cf8b 100644 --- a/conf/daemon/gstfsd +++ b/conf/daemon/gstfsd @@ -3,7 +3,7 @@ # gstfsd - WebVirtCloud daemon for managing VM's filesystem # -import SocketServer +import socketserver import json import guestfs import re @@ -13,11 +13,11 @@ PORT = 16510 ADDRESS = "0.0.0.0" -class MyTCPServer(SocketServer.ThreadingTCPServer): +class MyTCPServer(socketserver.ThreadingTCPServer): allow_reuse_address = True -class MyTCPServerHandler(SocketServer.BaseRequestHandler): +class MyTCPServerHandler(socketserver.BaseRequestHandler): def handle(self): # recive data data = json.loads(self.request.recv(1024).strip()) @@ -42,9 +42,9 @@ class MyTCPServerHandler(SocketServer.BaseRequestHandler): if data['action'] == 'publickey': if not gfs.is_dir('/root/.ssh'): gfs.mkdir('/root/.ssh') - gfs.chmod(0700, "/root/.ssh") + gfs.chmod(700, "/root/.ssh") gfs.write('/root/.ssh/authorized_keys', data['key']) - gfs.chmod(0600, '/root/.ssh/authorized_keys') + gfs.chmod(600, '/root/.ssh/authorized_keys') self.request.sendall(json.dumps({'return': 'success'})) gfs.umount(part) except RuntimeError: @@ -52,7 +52,7 @@ class MyTCPServerHandler(SocketServer.BaseRequestHandler): gfs.shutdown() gfs.close() except RuntimeError as err: - self.request.sendall(json.dumps({'return': 'error', 'message': err.message})) + self.request.sendall(json.dumps({'return': 'error', 'message': err})) server = MyTCPServer((ADDRESS, PORT), MyTCPServerHandler) diff --git a/conf/requirements.txt b/conf/requirements.txt index fc57c17..11adabb 100644 --- a/conf/requirements.txt +++ b/conf/requirements.txt @@ -1,7 +1,8 @@ -Django==1.11.26 +Django==2.2.10 websockify==0.9.0 -gunicorn==19.9.0 -lxml==4.4.2 -libvirt-python==5.10.0 +gunicorn==20.0.4 +lxml==4.5.0 +libvirt-python==6.1.0 +six pytz rwlock diff --git a/conf/runit/secret_generator.py b/conf/runit/secret_generator.py index 830ba9d..2a5a8dc 100644 --- a/conf/runit/secret_generator.py +++ b/conf/runit/secret_generator.py @@ -1,4 +1,4 @@ import random, string haystack = string.ascii_letters + string.digits + string.punctuation -print(''.join([random.SystemRandom().choice(haystack.replace('/','').replace('\'', '').replace('\"','')) for _ in range(50)])) \ No newline at end of file +print(''.join([random.SystemRandom().choice(haystack.replace('/', '').replace('\'', '').replace('\"', '')) for _ in range(50)])) diff --git a/conf/supervisor/gstfsd.conf b/conf/supervisor/gstfsd.conf index 2834b30..094f41c 100644 --- a/conf/supervisor/gstfsd.conf +++ b/conf/supervisor/gstfsd.conf @@ -1,5 +1,5 @@ [program:gstfsd] -command=/usr/bin/python /usr/local/bin/gstfsd +command=/srv/webvirtcloud/venv/bin/python3 /usr/local/bin/gstfsd directory=/usr/local/bin user=root autostart=true diff --git a/conf/supervisor/webvirtcloud.conf b/conf/supervisor/webvirtcloud.conf index 2994bc9..692fe8a 100644 --- a/conf/supervisor/webvirtcloud.conf +++ b/conf/supervisor/webvirtcloud.conf @@ -7,7 +7,7 @@ autorestart=true redirect_stderr=true [program:novncd] -command=/srv/webvirtcloud/venv/bin/python /srv/webvirtcloud/console/novncd +command=/srv/webvirtcloud/venv/bin/python3 /srv/webvirtcloud/console/novncd directory=/srv/webvirtcloud user=www-data autostart=true diff --git a/console/novncd b/console/novncd index 0f205a0..15ac905 100755 --- a/console/novncd +++ b/console/novncd @@ -7,7 +7,7 @@ import django DIR_PATH = os.path.dirname(os.path.abspath(__file__)) ROOT_PATH = os.path.abspath(os.path.join(DIR_PATH, '..', '')) -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "webvirtcloud.settings") +os.environ["DJANGO_SETTINGS_MODULE"] = "webvirtcloud.settings" CERT = DIR_PATH + '/cert.pem' if ROOT_PATH not in sys.path: @@ -15,16 +15,16 @@ if ROOT_PATH not in sys.path: django.setup() -# VENV_PATH = ROOT_PATH + '/venv/lib/python2.7/site-packages' +# VENV_PATH = ROOT_PATH + '/venv/lib/python3.6/site-packages' # if VENV_PATH not in sys.path: # sys.path.append(VENV_PATH) import re -import Cookie import socket +from six.moves import http_cookies as Cookie from webvirtcloud.settings import WS_PORT, WS_HOST, WS_CERT from vrtManager.connection import CONN_SSH, CONN_SOCKET -from tunnel import Tunnel +from console.tunnel import Tunnel from optparse import OptionParser parser = OptionParser() @@ -127,12 +127,30 @@ def get_connection_infos(token): class CompatibilityMixIn(object): def _new_client(self, daemon, socket_factory): - cookie = Cookie.SimpleCookie() - cookie.load(self.headers.getheader('cookie')) - if 'token' not in cookie: - self.msg('No token cookie found !') - return False - token = cookie['token'].value + # NoVNC uses it's own convention that forward token + # from the request to a cookie header, we should check + # also for this behavior + hcookie = self.headers.get('cookie') + if hcookie: + cookie = Cookie.SimpleCookie() + for hcookie_part in hcookie.split(';'): + hcookie_part = hcookie_part.lstrip() + try: + cookie.load(hcookie_part) + except Cookie.CookieError: + # NOTE(stgleb): Do not print out cookie content + # for security reasons. + self.msg('Found malformed cookie') + else: + if 'token' in cookie: + token = cookie['token'].value + + # cookie = Cookie.SimpleCookie() + # cookie.load(self.headers.getheader('cookie')) + # if 'token' not in cookie: + # self.msg('No token cookie found !') + # return False + # token = cookie['token'].value (connhost, connport, connuser, conntype, console_host, console_port, console_socket) = get_connection_infos(token) diff --git a/console/templates/console-base.html b/console/templates/console-base.html index e5c7ffe..5a79a01 100644 --- a/console/templates/console-base.html +++ b/console/templates/console-base.html @@ -35,7 +35,6 @@ margin-left: auto; margin-right: auto; display: block; - margin: auto; } #status { diff --git a/console/templates/console-spice-full.html b/console/templates/console-spice-full.html index 08ef3ee..aac780d 100644 --- a/console/templates/console-spice-full.html +++ b/console/templates/console-spice-full.html @@ -25,65 +25,28 @@ {% extends "console-base.html" %} {% load i18n %} {% load staticfiles %} + {% block head %} WebVirtCloud - Spice Client - Full - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -{% endblock %} - -{% block content %} - - - -
-
-
-
- -
- -
- -{% endblock %} - -{% block foot %} + + + + + + function fullscreen() { + var screen=document.getElementById('spice-screen'); + if(screen.requestFullscreen) { + screen.requestFullscreen(); + } else if(screen.mozRequestFullScreen) { + screen.mozRequestFullScreen(); + } else if(screen.webkitRequestFullscreen) { + screen.webkitRequestFullscreen(); + } else if(screen.msRequestFullscreen) { + screen.msRequestFullscreen(); + } + } + /* SPICE port event listeners + window.addEventListener('spice-port-data', function(event) { + // Here we convert data to text, but really we can obtain binary data also + var msg_text = arraybuffer_to_str(new Uint8Array(event.detail.data)); + DEBUG > 0 && console.log('SPICE port', event.detail.channel.portName, 'message text:', msg_text); + }); + + window.addEventListener('spice-port-event', function(event) { + DEBUG > 0 && console.log('SPICE port', event.detail.channel.portName, 'event data:', event.detail.spiceEvent); + }); + */ + document.getElementById("fullscreen_button").addEventListener('click', fullscreen); + document.getElementById('ctrlaltdel').addEventListener('click', function(){sendCtrlAltDel(sc);}); + document.getElementById('ctrlaltf1').addEventListener('click', function(){sendCtrlAltFN(0);}); + document.getElementById('ctrlaltf2').addEventListener('click', function(){sendCtrlAltFN(1);}); + document.getElementById('ctrlaltf3').addEventListener('click', function(){sendCtrlAltFN(2);}); + document.getElementById('ctrlaltf4').addEventListener('click', function(){sendCtrlAltFN(3);}); + document.getElementById('ctrlaltf5').addEventListener('click', function(){sendCtrlAltFN(4);}); + document.getElementById('ctrlaltf6').addEventListener('click', function(){sendCtrlAltFN(5);}); + document.getElementById('ctrlaltf7').addEventListener('click', function(){sendCtrlAltFN(6);}); + document.getElementById('ctrlaltf8').addEventListener('click', function(){sendCtrlAltFN(7);}); + document.getElementById('ctrlaltf9').addEventListener('click', function(){sendCtrlAltFN(8);}); + document.getElementById('ctrlaltf10').addEventListener('click', function(){sendCtrlAltFN(9);}); + document.getElementById('ctrlaltf11').addEventListener('click', function(){sendCtrlAltFN(10);}); + document.getElementById('ctrlaltf12').addEventListener('click', function(){sendCtrlAltFN(11);}); + + document.getElementById('connectButton').onclick = connect; + document.getElementById('show_console').onchange = toggle_console; + +{% endblock %} + +{% block content %} +
+ + + + + + +
+ +
+
+
+ +
+ +
+ +
+ +{% endblock %} + +{% block foot %} + {% endblock %} diff --git a/console/templates/console-spice-lite.html b/console/templates/console-spice-lite.html index f1e272c..d498f0f 100644 --- a/console/templates/console-spice-lite.html +++ b/console/templates/console-spice-lite.html @@ -25,56 +25,27 @@ {% extends "console-base.html" %} {% load i18n %} {% load staticfiles %} + {% block head %} - WebVirtCloud - Spice - Lite - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -{% endblock %} - -{% block content %} -
-
-
-
- -
- -
-{% endblock %} - -{% block foot %} + + + + {% endblock %} +{% block content %} +
+ +
+ +
+
+
+ +
+ +
+ +
+{% endblock %} + diff --git a/console/tunnel.py b/console/tunnel.py index a6ba2c8..c7c19d6 100644 --- a/console/tunnel.py +++ b/console/tunnel.py @@ -27,6 +27,7 @@ import os import socket import signal import logging +from functools import reduce class Tunnel(object): @@ -103,7 +104,7 @@ class Tunnel(object): logging.debug("Tunnel PID=%d OUTFD=%d ERRFD=%d", pid, fds[0].fileno(), errorfds[0].fileno()) - errorfds[0].setblocking(0) + errorfds[0].setblocking(False) self.outfd = fds[0] self.errfd = errorfds[0] diff --git a/console/views.py b/console/views.py index 85b0a27..a27a562 100644 --- a/console/views.py +++ b/console/views.py @@ -33,7 +33,7 @@ def console(request): console_type = conn.get_console_type() console_websocket_port = conn.get_console_websocket_port() console_passwd = conn.get_console_passwd() - except libvirtError as lib_err: + except libvirtError: console_type = None console_websocket_port = None console_passwd = None diff --git a/create/forms.py b/create/forms.py index a869ca4..21695e2 100644 --- a/create/forms.py +++ b/create/forms.py @@ -62,4 +62,3 @@ class NewVMForm(forms.Form): elif len(name) > 64: raise forms.ValidationError(_('The name of the virtual machine must not exceed 20 characters')) return name - diff --git a/create/migrations/0001_initial.py b/create/migrations/0001_initial.py index 030ee30..102bc96 100644 --- a/create/migrations/0001_initial.py +++ b/create/migrations/0001_initial.py @@ -1,11 +1,12 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals +# Generated by Django 2.2.10 on 2020-01-28 07:01 -from django.db import models, migrations +from django.db import migrations, models class Migration(migrations.Migration): + initial = True + dependencies = [ ] @@ -13,14 +14,11 @@ class Migration(migrations.Migration): migrations.CreateModel( name='Flavor', fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('label', models.CharField(max_length=12)), ('memory', models.IntegerField()), ('vcpu', models.IntegerField()), ('disk', models.IntegerField()), ], - options={ - }, - bases=(models.Model,), ), ] diff --git a/create/migrations/0002_auto_20150325_0921.py b/create/migrations/0002_addFlavors.py similarity index 92% rename from create/migrations/0002_auto_20150325_0921.py rename to create/migrations/0002_addFlavors.py index 5594060..f3ea4b3 100644 --- a/create/migrations/0002_auto_20150325_0921.py +++ b/create/migrations/0002_addFlavors.py @@ -1,5 +1,4 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals +# Generated by Django 2.2.10 on 2020-01-28 07:01 from django.db import migrations @@ -28,4 +27,4 @@ class Migration(migrations.Migration): operations = [ migrations.RunPython(add_favors), - ] + ] \ No newline at end of file diff --git a/create/models.py b/create/models.py index 0572fdd..80bf9f3 100644 --- a/create/models.py +++ b/create/models.py @@ -1,11 +1,11 @@ -from django.db import models +from django.db.models import Model, CharField, IntegerField -class Flavor(models.Model): - label = models.CharField(max_length=12) - memory = models.IntegerField() - vcpu = models.IntegerField() - disk = models.IntegerField() +class Flavor(Model): + label = CharField(max_length=12) + memory = IntegerField() + vcpu = IntegerField() + disk = IntegerField() def __unicode__(self): return self.name diff --git a/create/templates/create_instance_w1.html b/create/templates/create_instance_w1.html index e4a5f2c..a75a0b2 100644 --- a/create/templates/create_instance_w1.html +++ b/create/templates/create_instance_w1.html @@ -94,7 +94,7 @@
-
+
diff --git a/create/templates/create_instance_w2.html b/create/templates/create_instance_w2.html index 09a9484..9e00d7c 100644 --- a/create/templates/create_instance_w2.html +++ b/create/templates/create_instance_w2.html @@ -120,7 +120,7 @@
@@ -792,7 +792,7 @@ $.each(input_value.split(','), function (index, value) { let li = '
  • eth' + counter + ' -> ' + value + ' ' + - '
  • '; + ''; selected_list_html += li; counter++; }); diff --git a/create/views.py b/create/views.py index c66484f..e2e81fb 100644 --- a/create/views.py +++ b/create/views.py @@ -19,9 +19,13 @@ from webvirtcloud.settings import QEMU_CONSOLE_DEFAULT_TYPE from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_IO from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_DISCARD +from webvirtcloud.settings import INSTANCE_ARCH_DEFAULT_TYPE +from webvirtcloud.settings import INSTANCE_FIRMWARE_DEFAULT_TYPE + from django.contrib import messages from logs.views import addlogmsg + @login_required def create_instance_select_type(request, compute_id): @@ -45,8 +49,9 @@ def create_instance_select_type(request, compute_id): all_hypervisors = conn.get_hypervisors_machines() # Supported hypervisors by webvirtcloud: i686, x86_64(for now) supported_arch = ["x86_64", "i686", "aarch64", "armv7l", "ppc64", "ppc64le", "s390x"] - hypervisors = [hpv for hpv in all_hypervisors.keys() if hpv in supported_arch ] + hypervisors = [hpv for hpv in all_hypervisors.keys() if hpv in supported_arch] default_machine = INSTANCE_MACHINE_DEFAULT_TYPE + default_arch = INSTANCE_ARCH_DEFAULT_TYPE if request.method == 'POST': if 'create_xml' in request.POST: @@ -63,18 +68,21 @@ def create_instance_select_type(request, compute_id): conn._defineXML(xml) return HttpResponseRedirect(reverse('instance', args=[compute_id, name])) except libvirtError as lib_err: - error_messages.append(lib_err.message) + error_messages.append(lib_err) except libvirtError as lib_err: error_messages.append(lib_err) return render(request, 'create_instance_w1.html', locals()) + @login_required def create_instance(request, compute_id, arch, machine): """ :param request: :param compute_id: + :param arch: + :param machine: :return: """ if not request.user.is_superuser: @@ -96,6 +104,7 @@ def create_instance(request, compute_id, arch, machine): compute.password, compute.type) + default_firmware = INSTANCE_FIRMWARE_DEFAULT_TYPE default_cpu_mode = INSTANCE_CPU_DEFAULT_MODE instances = conn.get_instances() videos = conn.get_video_models(arch, machine) @@ -189,7 +198,7 @@ def create_instance(request, compute_id, arch, machine): volume_list.append(volume) is_disk_created = True except libvirtError as lib_err: - error_messages.append(lib_err.message) + error_messages.append(lib_err) elif data['template']: templ_path = conn.get_volume_path(data['template']) dest_vol = conn.get_volume_path(data["name"] + ".img", data['storage']) @@ -221,7 +230,7 @@ def create_instance(request, compute_id, arch, machine): volume['bus'] = request.POST.get('bus' + str(idx), '') volume_list.append(volume) except libvirtError as lib_err: - error_messages.append(lib_err.message) + error_messages.append(lib_err) if data['cache_mode'] not in conn.get_cache_modes(): error_msg = _("Invalid cache mode") error_messages.append(error_msg) diff --git a/dev/requirements.txt b/dev/requirements.txt index e88d0b2..d56ba0a 100644 --- a/dev/requirements.txt +++ b/dev/requirements.txt @@ -1,4 +1,4 @@ -r ../conf/requirements.txt -pep8==1.7.1 +pycodestyle pyflakes==2.1.1 -pylint==1.9.4 +pylint==2.4.4 diff --git a/gunicorn.conf.py b/gunicorn.conf.py index 8c07259..90bd54e 100644 --- a/gunicorn.conf.py +++ b/gunicorn.conf.py @@ -20,7 +20,7 @@ import os # range. # -#bind = 'unix:/srv/webvirtcloud/venv/wvcloud.socket' +# bind = 'unix:/srv/webvirtcloud/venv/wvcloud.socket' bind = '127.0.0.1:8000' backlog = 2048 diff --git a/instances/migrations/0001_initial.py b/instances/migrations/0001_initial.py index fe3c00f..e27f7aa 100644 --- a/instances/migrations/0001_initial.py +++ b/instances/migrations/0001_initial.py @@ -1,11 +1,13 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals +# Generated by Django 2.2.10 on 2020-01-28 07:01 -from django.db import models, migrations +from django.db import migrations, models +import django.db.models.deletion class Migration(migrations.Migration): + initial = True + dependencies = [ ('computes', '0001_initial'), ] @@ -14,13 +16,12 @@ class Migration(migrations.Migration): migrations.CreateModel( name='Instance', fields=[ - ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('name', models.CharField(max_length=20)), + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=120)), ('uuid', models.CharField(max_length=36)), - ('compute', models.ForeignKey(to='computes.Compute')), + ('is_template', models.BooleanField(default=False)), + ('created', models.DateField(auto_now_add=True)), + ('compute', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='computes.Compute')), ], - options={ - }, - bases=(models.Model,), ), ] diff --git a/instances/migrations/0002_instance_is_template.py b/instances/migrations/0002_instance_is_template.py deleted file mode 100644 index cbf2cdd..0000000 --- a/instances/migrations/0002_instance_is_template.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import models, migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('instances', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='instance', - name='is_template', - field=models.BooleanField(default=False), - ), - ] diff --git a/instances/migrations/0003_instance_created.py b/instances/migrations/0003_instance_created.py deleted file mode 100644 index 32d4ac9..0000000 --- a/instances/migrations/0003_instance_created.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import migrations, models -import datetime - - -class Migration(migrations.Migration): - - dependencies = [ - ('instances', '0002_instance_is_template'), - ] - - operations = [ - migrations.AddField( - model_name='instance', - name='created', - field=models.DateField(default=datetime.datetime(2017, 10, 26, 8, 5, 55, 797326), auto_now_add=True), - preserve_default=False, - ), - ] diff --git a/instances/migrations/0004_auto_20180724_1136.py b/instances/migrations/0004_auto_20180724_1136.py deleted file mode 100644 index 82480cd..0000000 --- a/instances/migrations/0004_auto_20180724_1136.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.11.13 on 2018-07-24 11:36 -from __future__ import unicode_literals - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('instances', '0003_instance_created'), - ] - - operations = [ - migrations.AlterField( - model_name='instance', - name='name', - field=models.CharField(max_length=120), - ), - ] diff --git a/instances/models.py b/instances/models.py index b11c860..436ab41 100644 --- a/instances/models.py +++ b/instances/models.py @@ -1,13 +1,13 @@ -from django.db import models +from django.db.models import Model, ForeignKey, CharField, BooleanField, DateField, CASCADE from computes.models import Compute -class Instance(models.Model): - compute = models.ForeignKey(Compute, on_delete=models.CASCADE) - name = models.CharField(max_length=120) - uuid = models.CharField(max_length=36) - is_template = models.BooleanField(default=False) - created = models.DateField(auto_now_add=True) +class Instance(Model): + compute = ForeignKey(Compute, on_delete=CASCADE) + name = CharField(max_length=120) + uuid = CharField(max_length=36) + is_template = BooleanField(default=False) + created = DateField(auto_now_add=True) def __unicode__(self): return self.name diff --git a/instances/templates/edit_instance_volume.html b/instances/templates/edit_instance_volume.html index e0b5fd9..5b023e5 100644 --- a/instances/templates/edit_instance_volume.html +++ b/instances/templates/edit_instance_volume.html @@ -48,7 +48,7 @@
    - {% for bus in bus_host %} {% endfor %} @@ -110,6 +110,7 @@
    + diff --git a/instances/templates/instance.html b/instances/templates/instance.html index c3cb9c6..c3307c1 100644 --- a/instances/templates/instance.html +++ b/instances/templates/instance.html @@ -510,7 +510,7 @@
    {% if request.user.is_superuser or request.user.is_staff or userinstance.is_change %}
    {% csrf_token %} -

    {% trans "Disk allocation (B):" %}

    +

    {% trans "Disk allocation (GB):" %}

    {% for disk in disks %}
    @@ -704,25 +704,25 @@

    {% trans 'Boot Order' %}

    -
    {% csrf_token %} -
    -
    - {% ifequal status 5 %} -

    {% trans "Enable Boot Menu for your instance when it starts up " %} - {% ifequal bootmenu 0 %} - - {% else %} - - {% endifequal %} + {% csrf_token %} +

    +
    + {% ifequal status 5 %} +

    {% trans "Enable Boot Menu for your instance when it starts up " %} + {% ifequal bootmenu 0 %} + {% else %} - {% ifequal bootmenu 0 %} -

    {% trans "**** Please shutdown instance to modify boot menu ****" %}

    - {% endifequal %} + {% endifequal %} -
    + {% else %} + {% ifequal bootmenu 0 %} +

    {% trans "**** Please shutdown instance to modify boot menu ****" %}

    + {% endifequal %} + {% endifequal %}
    - -

    +
    + + {% ifequal bootmenu 1 %}
    @@ -841,12 +841,14 @@
    - - - - - - + + + + + + + + {% for disk in disks %} @@ -1169,7 +1171,7 @@ {% endif %} -

    +

    {% trans "If you need to edit xml please Power Off the instance" %}

    @@ -1354,7 +1356,7 @@
    {% else %}
    - {% for name in clone_free_names %} {% endfor %} @@ -1730,7 +1732,7 @@ $.getJSON('{% url 'random_mac_address' %}', function (data) { $('input[name="' + net + '"]').val(data['mac']); }); - }; + }
    {% trans "Device" %}{% trans "Used" %}{% trans "Capacity" %}{% trans "Storage" %}{% trans "Source" %}{% trans "Action" %}
    {% trans "Device" %}{% trans "Used" %}{% trans "Capacity" %}{% trans "Storage" %}{% trans "Source" %}{% trans "Action" %}