diff --git a/accounts/apps.py b/accounts/apps.py
index 0192800..446ec40 100644
--- a/accounts/apps.py
+++ b/accounts/apps.py
@@ -3,48 +3,59 @@ from django.db.models.signals import post_migrate
def apply_change_password(sender, **kwargs):
- '''
+ """
Apply new change_password permission for all users
Depending on settings SHOW_PROFILE_EDIT_PASSWORD
- '''
+ """
from django.conf import settings
from django.contrib.auth.models import Permission, User
- if hasattr(settings, 'SHOW_PROFILE_EDIT_PASSWORD'):
- print('\033[1m! \033[92mSHOW_PROFILE_EDIT_PASSWORD is found inside settings.py\033[0m')
- print('\033[1m* \033[92mApplying permission can_change_password for all users\033[0m')
+
+ if hasattr(settings, "SHOW_PROFILE_EDIT_PASSWORD"):
+ print("\033[1m! \033[92mSHOW_PROFILE_EDIT_PASSWORD is found inside settings.py\033[0m")
+ print("\033[1m* \033[92mApplying permission can_change_password for all users\033[0m")
users = User.objects.all()
- permission = Permission.objects.get(codename='change_password')
+ permission = Permission.objects.get(codename="change_password")
if settings.SHOW_PROFILE_EDIT_PASSWORD:
- print('\033[1m! \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:
user.user_permissions.add(permission)
else:
- print('\033[1m* \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:
user.user_permissions.remove(permission)
- print('\033[1m! Don`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):
- '''
+ """
Create initial admin user
- '''
+ """
from accounts.models import UserAttributes
from django.contrib.auth.models import User
- plan = kwargs.get('plan', [])
+ plan = kwargs.get("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:
- print('\033[1m* \033[92mCreating default admin user\033[0m')
- 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()
+ print("\033[1m* \033[92mCreating default admin user\033[0m")
+ 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()
break
class AccountsConfig(AppConfig):
- name = 'accounts'
- verbose_name = 'Accounts'
+ name = "accounts"
+ verbose_name = "Accounts"
def ready(self):
post_migrate.connect(create_admin, sender=self)
diff --git a/accounts/forms.py b/accounts/forms.py
index cbd3425..d4c7e56 100644
--- a/accounts/forms.py
+++ b/accounts/forms.py
@@ -12,52 +12,52 @@ class UserInstanceForm(ModelForm):
super(UserInstanceForm, self).__init__(*args, **kwargs)
# Make user and instance fields not editable after creation
- instance = getattr(self, 'instance', None)
+ instance = getattr(self, "instance", None)
if instance and instance.id is not None:
- self.fields['user'].disabled = True
- self.fields['instance'].disabled = True
+ self.fields["user"].disabled = True
+ self.fields["instance"].disabled = True
def clean_instance(self):
- instance = self.cleaned_data['instance']
- if app_settings.ALLOW_INSTANCE_MULTIPLE_OWNER == 'False':
+ instance = self.cleaned_data["instance"]
+ if app_settings.ALLOW_INSTANCE_MULTIPLE_OWNER == "False":
exists = UserInstance.objects.filter(instance=instance)
if exists:
- raise ValidationError(_('Instance owned by another user'))
+ raise ValidationError(_("Instance owned by another user"))
return instance
class Meta:
model = UserInstance
- fields = '__all__'
+ fields = "__all__"
class ProfileForm(ModelForm):
class Meta:
model = get_user_model()
- fields = ('first_name', 'last_name', 'email')
+ fields = ("first_name", "last_name", "email")
class UserSSHKeyForm(ModelForm):
def __init__(self, *args, **kwargs):
- self.user = kwargs.pop('user', None)
+ self.user = kwargs.pop("user", None)
self.publickeys = UserSSHKey.objects.filter(user=self.user)
super().__init__(*args, **kwargs)
def clean_keyname(self):
for key in self.publickeys:
- if self.cleaned_data['keyname'] == key.keyname:
+ if self.cleaned_data["keyname"] == key.keyname:
raise ValidationError(_("Key name already exist"))
- return self.cleaned_data['keyname']
+ return self.cleaned_data["keyname"]
def clean_keypublic(self):
for key in self.publickeys:
- if self.cleaned_data['keypublic'] == key.keypublic:
+ if self.cleaned_data["keypublic"] == key.keypublic:
raise ValidationError(_("Public key already exist"))
- if not validate_ssh_key(self.cleaned_data['keypublic']):
- raise ValidationError(_('Invalid key'))
- return self.cleaned_data['keypublic']
+ if not validate_ssh_key(self.cleaned_data["keypublic"]):
+ raise ValidationError(_("Invalid key"))
+ return self.cleaned_data["keypublic"]
def save(self, commit=True):
ssh_key = super().save(commit=False)
@@ -68,8 +68,8 @@ class UserSSHKeyForm(ModelForm):
class Meta:
model = UserSSHKey
- fields = ('keyname', 'keypublic')
+ fields = ("keyname", "keypublic")
class EmailOTPForm(Form):
- email = EmailField(label=_('Email'))
+ email = EmailField(label=_("Email"))
diff --git a/accounts/models.py b/accounts/models.py
index 1fcc880..88cbb23 100644
--- a/accounts/models.py
+++ b/accounts/models.py
@@ -7,7 +7,7 @@ from instances.models import Instance
class UserInstanceManager(models.Manager):
def get_queryset(self):
- return super().get_queryset().select_related('instance', 'user')
+ return super().get_queryset().select_related("instance", "user")
class UserInstance(models.Model):
@@ -20,16 +20,19 @@ class UserInstance(models.Model):
objects = UserInstanceManager()
def __str__(self):
- return _('Instance "%(inst)s" of user %(user)s') % {"inst": self.instance, "user": self.user}
+ return _('Instance "%(inst)s" of user %(user)s') % {
+ "inst": self.instance,
+ "user": self.user,
+ }
class Meta:
- unique_together = ['user', 'instance']
+ unique_together = ["user", "instance"]
class UserSSHKey(models.Model):
user = models.ForeignKey(User, on_delete=models.DO_NOTHING)
- keyname = models.CharField(_('key name'), max_length=25)
- keypublic = models.CharField(_('public key'), max_length=500)
+ keyname = models.CharField(_("key name"), max_length=25)
+ keypublic = models.CharField(_("public key"), max_length=500)
def __str__(self):
return self.keyname
@@ -38,26 +41,26 @@ class UserSSHKey(models.Model):
class UserAttributes(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
can_clone_instances = models.BooleanField(default=True)
- max_instances = models.IntegerField(_('max instances'),
- default=2,
- help_text=_("-1 for unlimited. Any integer value"),
- validators=[
- MinValueValidator(-1),
- ])
+ max_instances = models.IntegerField(
+ _("max instances"),
+ default=2,
+ help_text=_("-1 for unlimited. Any integer value"),
+ validators=[MinValueValidator(-1)],
+ )
max_cpus = models.IntegerField(
- _('max CPUs'),
+ _("max CPUs"),
default=2,
help_text=_("-1 for unlimited. Any integer value"),
validators=[MinValueValidator(-1)],
)
max_memory = models.IntegerField(
- _('max memory'),
+ _("max memory"),
default=2048,
help_text=_("-1 for unlimited. Any integer value"),
validators=[MinValueValidator(-1)],
)
max_disk_size = models.IntegerField(
- _('max disk size'),
+ _("max disk size"),
default=20,
help_text=_("-1 for unlimited. Any integer value"),
validators=[MinValueValidator(-1)],
@@ -71,8 +74,9 @@ class PermissionSet(models.Model):
"""
Dummy model for holding set of permissions we need to be automatically added by Django
"""
+
class Meta:
default_permissions = ()
- permissions = (('change_password', _('Can change password')), )
+ permissions = (("change_password", _("Can change password")),)
managed = False
diff --git a/accounts/templates/accounts/email/otp.html b/accounts/templates/accounts/email/otp.html
index 2833194..c80ec14 100644
--- a/accounts/templates/accounts/email/otp.html
+++ b/accounts/templates/accounts/email/otp.html
@@ -4,4 +4,6 @@
Scan this QR code to get OTP for account '{{ user }}'
{% endblocktrans %}
-{% qr_from_text totp_url %}
\ No newline at end of file
+{% qr_from_text totp_url %}
+
{% trans 'Some e-mail clients does not render SVG, also generating PNG.' %}
+{% qr_from_text totp_url size="s" image_format="png" error_correction="M" %}
diff --git a/accounts/tests.py b/accounts/tests.py
index 2419990..3b7ed6b 100644
--- a/accounts/tests.py
+++ b/accounts/tests.py
@@ -23,15 +23,15 @@ class AccountsTestCase(TestCase):
# Add users for testing purposes
User = get_user_model()
cls.admin_user = User.objects.get(pk=1)
- cls.test_user = User.objects.create_user(username='test', password='test')
+ cls.test_user = User.objects.create_user(username="test", password="test")
# Add localhost compute
cls.compute = Compute(
- name='test-compute',
- hostname='localhost',
- login='',
- password='',
- details='local',
+ name="test-compute",
+ hostname="localhost",
+ login="",
+ password="",
+ details="local",
type=4,
)
cls.compute.save()
@@ -45,17 +45,17 @@ class AccountsTestCase(TestCase):
# Add disks for testing
cls.connection.create_volume(
- 'default',
- 'test-volume',
+ "default",
+ "test-volume",
1,
- 'qcow2',
+ "qcow2",
False,
0,
0,
)
# XML for testing vm
- with open('conf/test-vm.xml', 'r') as f:
+ with open("conf/test-vm.xml", "r") as f:
cls.xml = f.read()
# Create testing vm from XML
@@ -71,80 +71,90 @@ class AccountsTestCase(TestCase):
super().tearDownClass()
def setUp(self):
- self.client.login(username='admin', password='admin')
- permission = Permission.objects.get(codename='change_password')
+ self.client.login(username="admin", password="admin")
+ permission = Permission.objects.get(codename="change_password")
self.test_user.user_permissions.add(permission)
- self.rsa_key = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC6OOdbfv27QVnSC6sKxGaHb6YFc+3gxCkyVR3cTSXE/n5BEGf8aOgBpepULWa1RZfxYHY14PlKULDygdXSdrrR2kNSwoKz/Oo4d+3EE92L7ocl1+djZbptzgWgtw1OseLwbFik+iKlIdqPsH+IUQvX7yV545ZQtAP8Qj1R+uCqkw== test@test'
- self.ecdsa_key = 'ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJc5xpT3R0iFJYNZbmWgAiDlHquX/BcV1kVTsnBfiMsZgU3lGaqz2eb7IBcir/dxGnsVENTTmPQ6sNcxLxT9kkQ= realgecko@archlinux'
+ self.rsa_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC6OOdbfv27QVnSC6sKxGaHb6YFc+3gxCkyVR3cTSXE/n5BEGf8aOgBpepULWa1RZfxYHY14PlKULDygdXSdrrR2kNSwoKz/Oo4d+3EE92L7ocl1+djZbptzgWgtw1OseLwbFik+iKlIdqPsH+IUQvX7yV545ZQtAP8Qj1R+uCqkw== test@test"
+ self.ecdsa_key = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJc5xpT3R0iFJYNZbmWgAiDlHquX/BcV1kVTsnBfiMsZgU3lGaqz2eb7IBcir/dxGnsVENTTmPQ6sNcxLxT9kkQ= realgecko@archlinux"
def test_profile(self):
- response = self.client.get(reverse('accounts:profile'))
+ response = self.client.get(reverse("accounts:profile"))
self.assertEqual(response.status_code, 200)
- response = self.client.get(reverse('accounts:account', args=[self.test_user.id]))
+ response = self.client.get(
+ reverse("accounts:account", args=[self.test_user.id])
+ )
self.assertEqual(response.status_code, 200)
def test_account_with_otp(self):
settings.OTP_ENABLED = True
- response = self.client.get(reverse('accounts:account', args=[self.test_user.id]))
+ response = self.client.get(
+ reverse("accounts:account", args=[self.test_user.id])
+ )
self.assertEqual(response.status_code, 200)
def test_login_logout(self):
client = Client()
- response = client.post(reverse("accounts:login"), {"username": "test", "password": "test"})
- self.assertRedirects(response, reverse('accounts:profile'))
+ response = client.post(
+ reverse("accounts:login"), {"username": "test", "password": "test"}
+ )
+ self.assertRedirects(response, reverse("accounts:profile"))
- response = client.get(reverse('accounts:logout'))
- self.assertRedirects(response, reverse('accounts:login'))
+ response = client.get(reverse("accounts:logout"))
+ self.assertRedirects(response, reverse("accounts:login"))
def test_change_password(self):
self.client.force_login(self.test_user)
- response = self.client.get(reverse('accounts:change_password'))
+ response = self.client.get(reverse("accounts:change_password"))
self.assertEqual(response.status_code, 200)
response = self.client.post(
- reverse('accounts:change_password'),
+ reverse("accounts:change_password"),
{
- 'old_password': 'wrongpass',
- 'new_password1': 'newpw',
- 'new_password2': 'newpw',
+ "old_password": "wrongpass",
+ "new_password1": "newpw",
+ "new_password2": "newpw",
},
)
self.assertEqual(response.status_code, 200)
response = self.client.post(
- reverse('accounts:change_password'),
+ reverse("accounts:change_password"),
{
- 'old_password': 'test',
- 'new_password1': 'newpw',
- 'new_password2': 'newpw',
+ "old_password": "test",
+ "new_password1": "newpw",
+ "new_password2": "newpw",
},
)
- self.assertRedirects(response, reverse('accounts:profile'))
+ self.assertRedirects(response, reverse("accounts:profile"))
self.client.logout()
- logged_in = self.client.login(username='test', password='newpw')
+ logged_in = self.client.login(username="test", password="newpw")
self.assertTrue(logged_in)
def test_user_instance_create_update_delete(self):
# create
- response = self.client.get(reverse('accounts:user_instance_create', args=[self.test_user.id]))
+ response = self.client.get(
+ reverse("accounts:user_instance_create", args=[self.test_user.id])
+ )
self.assertEqual(response.status_code, 200)
response = self.client.post(
- reverse('accounts:user_instance_create', args=[self.test_user.id]),
+ reverse("accounts:user_instance_create", args=[self.test_user.id]),
{
- 'user': self.test_user.id,
- 'instance': self.instance.id,
- 'is_change': False,
- 'is_delete': False,
- 'is_vnc': False,
+ "user": self.test_user.id,
+ "instance": self.instance.id,
+ "is_change": False,
+ "is_delete": False,
+ "is_vnc": False,
},
)
- self.assertRedirects(response, reverse('accounts:account', args=[self.test_user.id]))
+ self.assertRedirects(
+ response, reverse("accounts:account", args=[self.test_user.id])
+ )
user_instance: UserInstance = UserInstance.objects.get(pk=1)
self.assertEqual(user_instance.user, self.test_user)
@@ -154,20 +164,24 @@ class AccountsTestCase(TestCase):
self.assertEqual(user_instance.is_vnc, False)
# update
- response = self.client.get(reverse('accounts:user_instance_update', args=[user_instance.id]))
+ response = self.client.get(
+ reverse("accounts:user_instance_update", args=[user_instance.id])
+ )
self.assertEqual(response.status_code, 200)
response = self.client.post(
- reverse('accounts:user_instance_update', args=[user_instance.id]),
+ reverse("accounts:user_instance_update", args=[user_instance.id]),
{
- 'user': self.test_user.id,
- 'instance': self.instance.id,
- 'is_change': True,
- 'is_delete': True,
- 'is_vnc': True,
+ "user": self.test_user.id,
+ "instance": self.instance.id,
+ "is_change": True,
+ "is_delete": True,
+ "is_vnc": True,
},
)
- self.assertRedirects(response, reverse('accounts:account', args=[self.test_user.id]))
+ self.assertRedirects(
+ response, reverse("accounts:account", args=[self.test_user.id])
+ )
user_instance: UserInstance = UserInstance.objects.get(pk=1)
self.assertEqual(user_instance.user, self.test_user)
@@ -177,91 +191,118 @@ class AccountsTestCase(TestCase):
self.assertEqual(user_instance.is_vnc, True)
# delete
- response = self.client.get(reverse('accounts:user_instance_delete', args=[user_instance.id]))
+ response = self.client.get(
+ reverse("accounts:user_instance_delete", args=[user_instance.id])
+ )
self.assertEqual(response.status_code, 200)
- response = self.client.post(reverse('accounts:user_instance_delete', args=[user_instance.id]))
- self.assertRedirects(response, reverse('accounts:account', args=[self.test_user.id]))
+ response = self.client.post(
+ reverse("accounts:user_instance_delete", args=[user_instance.id])
+ )
+ self.assertRedirects(
+ response, reverse("accounts:account", args=[self.test_user.id])
+ )
# test 'next' redirect during deletion
- user_instance = UserInstance.objects.create(user=self.test_user, instance=self.instance)
+ user_instance = UserInstance.objects.create(
+ user=self.test_user, instance=self.instance
+ )
response = self.client.post(
- reverse('accounts:user_instance_delete', args=[user_instance.id]) + '?next=' + reverse('index'))
- self.assertRedirects(response, reverse('index'))
+ reverse("accounts:user_instance_delete", args=[user_instance.id])
+ + "?next="
+ + reverse("index")
+ )
+ self.assertRedirects(response, reverse("index"))
def test_update_user_profile(self):
self.client.force_login(self.test_user)
- user = get_user_model().objects.get(username='test')
- self.assertEqual(user.first_name, '')
- self.assertEqual(user.last_name, '')
- self.assertEqual(user.email, '')
+ user = get_user_model().objects.get(username="test")
+ self.assertEqual(user.first_name, "")
+ self.assertEqual(user.last_name, "")
+ self.assertEqual(user.email, "")
- response = self.client.post(reverse('accounts:profile'), {
- 'first_name': 'first name',
- 'last_name': 'last name',
- 'email': 'email@mail.mail',
- })
- self.assertRedirects(response, reverse('accounts:profile'))
+ response = self.client.post(
+ reverse("accounts:profile"),
+ {
+ "first_name": "first name",
+ "last_name": "last name",
+ "email": "email@mail.mail",
+ },
+ )
+ self.assertRedirects(response, reverse("accounts:profile"))
- user = get_user_model().objects.get(username='test')
- self.assertEqual(user.first_name, 'first name')
- self.assertEqual(user.last_name, 'last name')
- self.assertEqual(user.email, 'email@mail.mail')
+ user = get_user_model().objects.get(username="test")
+ self.assertEqual(user.first_name, "first name")
+ self.assertEqual(user.last_name, "last name")
+ self.assertEqual(user.email, "email@mail.mail")
def test_create_delete_ssh_key(self):
- response = self.client.get(reverse('accounts:ssh_key_create'))
+ response = self.client.get(reverse("accounts:ssh_key_create"))
self.assertEqual(response.status_code, 200)
- response = self.client.post(reverse('accounts:ssh_key_create'), {
- 'keyname': 'keyname',
- 'keypublic': self.rsa_key,
- })
- self.assertRedirects(response, reverse('accounts:profile'))
+ response = self.client.post(
+ reverse("accounts:ssh_key_create"),
+ {
+ "keyname": "keyname",
+ "keypublic": self.rsa_key,
+ },
+ )
+ self.assertRedirects(response, reverse("accounts:profile"))
key = UserSSHKey.objects.get(pk=1)
- self.assertEqual(key.keyname, 'keyname')
+ self.assertEqual(key.keyname, "keyname")
self.assertEqual(key.keypublic, self.rsa_key)
- response = self.client.get(reverse('accounts:ssh_key_delete', args=[1]))
+ response = self.client.get(reverse("accounts:ssh_key_delete", args=[1]))
self.assertEqual(response.status_code, 200)
- response = self.client.post(reverse('accounts:ssh_key_delete', args=[1]))
- self.assertRedirects(response, reverse('accounts:profile'))
+ response = self.client.post(reverse("accounts:ssh_key_delete", args=[1]))
+ self.assertRedirects(response, reverse("accounts:profile"))
def test_validate_ssh_key(self):
- self.assertFalse(validate_ssh_key(''))
- self.assertFalse(validate_ssh_key('ssh-rsa ABBA test@test'))
- self.assertFalse(validate_ssh_key('ssh-rsa AAAABwdzZGY= test@test'))
- self.assertFalse(validate_ssh_key('ssh-rsa AAA test@test'))
+ self.assertFalse(validate_ssh_key(""))
+ self.assertFalse(validate_ssh_key("ssh-rsa ABBA test@test"))
+ self.assertFalse(validate_ssh_key("ssh-rsa AAAABwdzZGY= test@test"))
+ self.assertFalse(validate_ssh_key("ssh-rsa AAA test@test"))
# validate ecdsa key
self.assertTrue(validate_ssh_key(self.ecdsa_key))
def test_forms(self):
# raise available validation errors for maximum coverage
- form = UserSSHKeyForm({'keyname': 'keyname', 'keypublic': self.rsa_key}, user=self.test_user)
+ form = UserSSHKeyForm(
+ {"keyname": "keyname", "keypublic": self.rsa_key}, user=self.test_user
+ )
form.save()
- form = UserSSHKeyForm({'keyname': 'keyname', 'keypublic': self.rsa_key}, user=self.test_user)
+ form = UserSSHKeyForm(
+ {"keyname": "keyname", "keypublic": self.rsa_key}, user=self.test_user
+ )
self.assertFalse(form.is_valid())
- form = UserSSHKeyForm({'keyname': 'keyname', 'keypublic': 'invalid key'}, user=self.test_user)
+ form = UserSSHKeyForm(
+ {"keyname": "keyname", "keypublic": "invalid key"}, user=self.test_user
+ )
self.assertFalse(form.is_valid())
- app_settings.ALLOW_INSTANCE_MULTIPLE_OWNER = 'False'
- form = UserInstanceForm({
- 'user': self.admin_user.id,
- 'instance': self.instance.id,
- 'is_change': False,
- 'is_delete': False,
- 'is_vnc': False,
- })
+ app_settings.ALLOW_INSTANCE_MULTIPLE_OWNER = "False"
+ form = UserInstanceForm(
+ {
+ "user": self.admin_user.id,
+ "instance": self.instance.id,
+ "is_change": False,
+ "is_delete": False,
+ "is_vnc": False,
+ }
+ )
form.save()
- form = UserInstanceForm({
- 'user': self.test_user.id,
- 'instance': self.instance.id,
- 'is_change': False,
- 'is_delete': False,
- 'is_vnc': False,
- })
+ form = UserInstanceForm(
+ {
+ "user": self.test_user.id,
+ "instance": self.instance.id,
+ "is_change": False,
+ "is_delete": False,
+ "is_vnc": False,
+ }
+ )
self.assertFalse(form.is_valid())
diff --git a/accounts/urls.py b/accounts/urls.py
index d98e75a..2fa8e26 100644
--- a/accounts/urls.py
+++ b/accounts/urls.py
@@ -5,29 +5,50 @@ from django_otp.forms import OTPAuthenticationForm
from . import views
-app_name = 'accounts'
+app_name = "accounts"
urlpatterns = [
- path('logout/', LogoutView.as_view(template_name='logout.html'), name='logout'),
- path('profile/', views.profile, name='profile'),
- path('profile//', views.account, name='account'),
- path('change_password/', views.change_password, name='change_password'),
- path('user_instance/create//', views.user_instance_create, name='user_instance_create'),
- path('user_instance//update/', views.user_instance_update, name='user_instance_update'),
- path('user_instance//delete/', views.user_instance_delete, name='user_instance_delete'),
- path('ssh_key/create/', views.ssh_key_create, name='ssh_key_create'),
- path('ssh_key//delete/', views.ssh_key_delete, name='ssh_key_delete'),
+ path("logout/", LogoutView.as_view(template_name="logout.html"), name="logout"),
+ path("profile/", views.profile, name="profile"),
+ path("profile//", views.account, name="account"),
+ path("change_password/", views.change_password, name="change_password"),
+ path(
+ "user_instance/create//",
+ views.user_instance_create,
+ name="user_instance_create",
+ ),
+ path(
+ "user_instance//update/",
+ views.user_instance_update,
+ name="user_instance_update",
+ ),
+ path(
+ "user_instance//delete/",
+ views.user_instance_delete,
+ name="user_instance_delete",
+ ),
+ path("ssh_key/create/", views.ssh_key_create, name="ssh_key_create"),
+ path("ssh_key//delete/", views.ssh_key_delete, name="ssh_key_delete"),
]
if settings.OTP_ENABLED:
urlpatterns += [
path(
- 'login/',
- LoginView.as_view(template_name='accounts/otp_login.html', authentication_form=OTPAuthenticationForm),
- name='login',
+ "login/",
+ LoginView.as_view(
+ template_name="accounts/otp_login.html",
+ authentication_form=OTPAuthenticationForm,
+ ),
+ name="login",
+ ),
+ path("email_otp/", views.email_otp, name="email_otp"),
+ path(
+ "admin_email_otp//",
+ views.admin_email_otp,
+ name="admin_email_otp",
),
- path('email_otp/', views.email_otp, name='email_otp'),
- path('admin_email_otp//', views.admin_email_otp, name='admin_email_otp'),
]
else:
- urlpatterns += path('login/', LoginView.as_view(template_name='login.html'), name='login'),
+ urlpatterns += (
+ path("login/", LoginView.as_view(template_name="login.html"), name="login"),
+ )
diff --git a/accounts/views.py b/accounts/views.py
index 8ca3ba7..c4979bf 100644
--- a/accounts/views.py
+++ b/accounts/views.py
@@ -172,7 +172,10 @@ def email_otp(request):
device = get_user_totp_device(user)
send_email_with_otp(user, device)
- messages.success(request, _("OTP Sent to %(email)s") % {"email": form.cleaned_data["email"]})
+ messages.success(
+ request,
+ _("OTP Sent to %(email)s") % {"email": form.cleaned_data["email"]}
+ )
return redirect("accounts:login")
return render(
@@ -191,7 +194,13 @@ def admin_email_otp(request, user_id):
device = get_user_totp_device(user)
if user.email != "":
send_email_with_otp(user, device)
- messages.success(request, _("OTP QR code was emailed to user %(user)s") % {"user": user})
+ messages.success(
+ request,
+ _("OTP QR code was emailed to user %(user)s") % {"user": user}
+ )
else:
- messages.error(request, _("User email not set, failed to send QR code"))
+ messages.error(
+ request,
+ _("User email not set, failed to send QR code")
+ )
return redirect("accounts:account", user.id)
diff --git a/admin/apps.py b/admin/apps.py
index 5bbf122..86bb5bc 100644
--- a/admin/apps.py
+++ b/admin/apps.py
@@ -2,4 +2,4 @@ from django.apps import AppConfig
class AdminConfig(AppConfig):
- name = 'admin'
+ name = "admin"
diff --git a/admin/models.py b/admin/models.py
index b743377..67fcdf9 100644
--- a/admin/models.py
+++ b/admin/models.py
@@ -7,7 +7,7 @@ class Permission(P):
"""
def __str__(self):
- return f'{self.content_type.app_label}: {self.name}'
+ return f"{self.content_type.app_label}: {self.name}"
class Meta:
proxy = True
diff --git a/admin/tests.py b/admin/tests.py
index b030436..92d261c 100644
--- a/admin/tests.py
+++ b/admin/tests.py
@@ -8,62 +8,66 @@ from accounts.models import UserAttributes
class AdminTestCase(TestCase):
def setUp(self):
- self.client.login(username='admin', password='admin')
+ self.client.login(username="admin", password="admin")
def test_group_list(self):
- response = self.client.get(reverse('admin:group_list'))
+ response = self.client.get(reverse("admin:group_list"))
self.assertEqual(response.status_code, 200)
def test_groups(self):
- response = self.client.get(reverse('admin:group_create'))
+ response = self.client.get(reverse("admin:group_create"))
self.assertEqual(response.status_code, 200)
- response = self.client.post(reverse('admin:group_create'), {'name': 'Test Group'})
- self.assertRedirects(response, reverse('admin:group_list'))
+ response = self.client.post(
+ reverse("admin:group_create"), {"name": "Test Group"}
+ )
+ self.assertRedirects(response, reverse("admin:group_list"))
- group = Group.objects.get(name='Test Group')
+ group = Group.objects.get(name="Test Group")
self.assertEqual(group.id, 1)
- response = self.client.get(reverse('admin:group_update', args=[1]))
+ response = self.client.get(reverse("admin:group_update", args=[1]))
self.assertEqual(response.status_code, 200)
- response = self.client.post(reverse('admin:group_update', args=[1]), {'name': 'Updated Group Test'})
- self.assertRedirects(response, reverse('admin:group_list'))
+ response = self.client.post(
+ reverse("admin:group_update", args=[1]), {"name": "Updated Group Test"}
+ )
+ self.assertRedirects(response, reverse("admin:group_list"))
group = Group.objects.get(id=1)
- self.assertEqual(group.name, 'Updated Group Test')
+ self.assertEqual(group.name, "Updated Group Test")
- response = self.client.get(reverse('admin:group_delete', args=[1]))
+ response = self.client.get(reverse("admin:group_delete", args=[1]))
self.assertEqual(response.status_code, 200)
- response = self.client.post(reverse('admin:group_delete', args=[1]))
- self.assertRedirects(response, reverse('admin:group_list'))
+ response = self.client.post(reverse("admin:group_delete", args=[1]))
+ self.assertRedirects(response, reverse("admin:group_list"))
with self.assertRaises(ObjectDoesNotExist):
Group.objects.get(id=1)
def test_user_list(self):
- response = self.client.get(reverse('admin:user_list'))
+ response = self.client.get(reverse("admin:user_list"))
self.assertEqual(response.status_code, 200)
def test_users(self):
- response = self.client.get(reverse('admin:user_create'))
+ response = self.client.get(reverse("admin:user_create"))
self.assertEqual(response.status_code, 200)
response = self.client.post(
- reverse('admin:user_create'),
+ reverse("admin:user_create"),
{
- 'username': 'test',
- 'password': 'test',
- 'max_instances': 1,
- 'max_cpus': 1,
- 'max_memory': 1024,
- 'max_disk_size': 4,
+ "username": "test",
+ "password": "test",
+ "max_instances": 1,
+ "max_cpus": 1,
+ "max_memory": 1024,
+ "max_disk_size": 4,
},
)
- self.assertRedirects(response, reverse('admin:user_list'))
+ self.assertRedirects(response, reverse("admin:user_list"))
- user = User.objects.get(username='test')
+ user = User.objects.get(username="test")
self.assertEqual(user.id, 2)
ua: UserAttributes = UserAttributes.objects.get(id=2)
@@ -73,23 +77,23 @@ class AdminTestCase(TestCase):
self.assertEqual(ua.max_memory, 1024)
self.assertEqual(ua.max_disk_size, 4)
- response = self.client.get(reverse('admin:user_update', args=[2]))
+ response = self.client.get(reverse("admin:user_update", args=[2]))
self.assertEqual(response.status_code, 200)
response = self.client.post(
- reverse('admin:user_update', args=[2]),
+ reverse("admin:user_update", args=[2]),
{
- 'username': 'utest',
- 'max_instances': 2,
- 'max_cpus': 2,
- 'max_memory': 2048,
- 'max_disk_size': 8,
+ "username": "utest",
+ "max_instances": 2,
+ "max_cpus": 2,
+ "max_memory": 2048,
+ "max_disk_size": 8,
},
)
- self.assertRedirects(response, reverse('admin:user_list'))
+ self.assertRedirects(response, reverse("admin:user_list"))
user = User.objects.get(id=2)
- self.assertEqual(user.username, 'utest')
+ self.assertEqual(user.username, "utest")
ua: UserAttributes = UserAttributes.objects.get(id=2)
self.assertEqual(ua.user_id, 2)
@@ -98,23 +102,23 @@ class AdminTestCase(TestCase):
self.assertEqual(ua.max_memory, 2048)
self.assertEqual(ua.max_disk_size, 8)
- response = self.client.get(reverse('admin:user_block', args=[2]))
+ response = self.client.get(reverse("admin:user_block", args=[2]))
user = User.objects.get(id=2)
self.assertFalse(user.is_active)
- response = self.client.get(reverse('admin:user_unblock', args=[2]))
+ response = self.client.get(reverse("admin:user_unblock", args=[2]))
user = User.objects.get(id=2)
self.assertTrue(user.is_active)
- response = self.client.get(reverse('admin:user_delete', args=[2]))
+ response = self.client.get(reverse("admin:user_delete", args=[2]))
self.assertEqual(response.status_code, 200)
- response = self.client.post(reverse('admin:user_delete', args=[2]))
- self.assertRedirects(response, reverse('admin:user_list'))
+ response = self.client.post(reverse("admin:user_delete", args=[2]))
+ self.assertRedirects(response, reverse("admin:user_list"))
with self.assertRaises(ObjectDoesNotExist):
User.objects.get(id=2)
def test_logs(self):
- response = self.client.get(reverse('admin:logs'))
+ response = self.client.get(reverse("admin:logs"))
self.assertEqual(response.status_code, 200)
diff --git a/admin/urls.py b/admin/urls.py
index 205cbc0..0b5ab41 100644
--- a/admin/urls.py
+++ b/admin/urls.py
@@ -3,16 +3,16 @@ from django.urls import path
from . import views
urlpatterns = [
- path('groups/', views.group_list, name='group_list'),
- path('groups/create/', views.group_create, name='group_create'),
- path('groups//update/', views.group_update, name='group_update'),
- path('groups//delete/', views.group_delete, name='group_delete'),
- path('users/', views.user_list, name='user_list'),
- path('users/create/', views.user_create, name='user_create'),
- path('users//update_password/', views.user_update_password, name='user_update_password'),
- path('users//update/', views.user_update, name='user_update'),
- path('users//delete/', views.user_delete, name='user_delete'),
- path('users//block/', views.user_block, name='user_block'),
- path('users//unblock/', views.user_unblock, name='user_unblock'),
- path('logs/', views.logs, name='logs'),
+ path("groups/", views.group_list, name="group_list"),
+ path("groups/create/", views.group_create, name="group_create"),
+ path("groups//update/", views.group_update, name="group_update"),
+ path("groups//delete/", views.group_delete, name="group_delete"),
+ path("users/", views.user_list, name="user_list"),
+ path("users/create/", views.user_create, name="user_create"),
+ path("users//update_password/", views.user_update_password, name="user_update_password"),
+ path("users//update/", views.user_update, name="user_update"),
+ path("users//delete/", views.user_delete, name="user_delete"),
+ path("users//block/", views.user_block, name="user_block"),
+ path("users//unblock/", views.user_unblock, name="user_unblock"),
+ path("logs/", views.logs, name="logs"),
]
diff --git a/admin/views.py b/admin/views.py
index c920890..bdb2294 100644
--- a/admin/views.py
+++ b/admin/views.py
@@ -107,7 +107,11 @@ def user_create(request):
return render(
request,
"admin/user_form.html",
- {"user_form": user_form, "attributes_form": attributes_form, "title": _("Create User")},
+ {
+ "user_form": user_form,
+ "attributes_form": attributes_form,
+ "title": _("Create User"),
+ },
)
@@ -116,7 +120,9 @@ def user_update(request, pk):
user = get_object_or_404(User, pk=pk)
attributes = UserAttributes.objects.get(user=user)
user_form = forms.UserForm(request.POST or None, instance=user)
- attributes_form = forms.UserAttributesForm(request.POST or None, instance=attributes)
+ attributes_form = forms.UserAttributesForm(
+ request.POST or None, instance=attributes
+ )
if user_form.is_valid() and attributes_form.is_valid():
user_form.save()
attributes_form.save()
@@ -126,7 +132,11 @@ def user_update(request, pk):
return render(
request,
"admin/user_form.html",
- {"user_form": user_form, "attributes_form": attributes_form, "title": _("Update User")},
+ {
+ "user_form": user_form,
+ "attributes_form": attributes_form,
+ "title": _("Update User"),
+ },
)
@@ -138,7 +148,10 @@ def user_update_password(request, pk):
if form.is_valid():
user = form.save()
update_session_auth_hash(request, user) # Important!
- messages.success(request, _("Password changed for %(user)s") % {"user": user.username})
+ messages.success(
+ request,
+ _("Password changed for %(user)s") % {"user": user.username}
+ )
return redirect("admin:user_list")
else:
messages.error(request, _("Wrong Data Provided"))
diff --git a/appsettings/apps.py b/appsettings/apps.py
index 2e5909e..2a61fca 100644
--- a/appsettings/apps.py
+++ b/appsettings/apps.py
@@ -2,4 +2,4 @@ from django.apps import AppConfig
class AppsettingsConfig(AppConfig):
- name = 'appsettings'
+ name = "appsettings"
diff --git a/appsettings/models.py b/appsettings/models.py
index a45827f..0cfb4e7 100644
--- a/appsettings/models.py
+++ b/appsettings/models.py
@@ -3,12 +3,11 @@ from django.utils.translation import gettext_lazy as _
class AppSettings(models.Model):
-
def choices_as_list(self):
- return self.choices.split(',')
+ return self.choices.split(",")
- name = models.CharField(_('name'), max_length=25, null=False)
- key = models.CharField(_('key'), db_index=True, max_length=50, unique=True)
- value = models.CharField(_('value'), max_length=25)
- choices = models.CharField(_('choices'), max_length=70)
- description = models.CharField(_('description'), max_length=100, null=True)
+ name = models.CharField(_("name"), max_length=25, null=False)
+ key = models.CharField(_("key"), db_index=True, max_length=50, unique=True)
+ value = models.CharField(_("value"), max_length=25)
+ choices = models.CharField(_("choices"), max_length=70)
+ description = models.CharField(_("description"), max_length=100, null=True)
diff --git a/appsettings/views.py b/appsettings/views.py
index 4fa8ded..70b6490 100644
--- a/appsettings/views.py
+++ b/appsettings/views.py
@@ -27,7 +27,9 @@ def appsettings(request):
addlogmsg(request.user.username, "-", "", err)
# 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 "SASS_DIR" in request.POST:
@@ -35,7 +37,9 @@ def appsettings(request):
sass_dir.value = request.POST.get("SASS_DIR", "")
sass_dir.save()
- msg = _("SASS directory path is changed. Now: %(dir)s") % {"dir": sass_dir.value}
+ msg = _("SASS directory path is changed. Now: %(dir)s") % {
+ "dir": sass_dir.value
+ }
messages.success(request, msg)
except Exception as err:
msg = err
@@ -47,15 +51,17 @@ def appsettings(request):
if "BOOTSTRAP_THEME" in request.POST:
theme = request.POST.get("BOOTSTRAP_THEME", "")
scss_var = f"@import '{sass_dir.value}/wvc-theme/{theme}/variables';"
- #scss_boot = f"@import '{sass_dir.value}/bootstrap/bootstrap.scss';"
+ # scss_boot = f"@import '{sass_dir.value}/bootstrap/bootstrap.scss';"
scss_boot = f"@import '{sass_dir.value}/bootstrap-overrides.scss';"
- scss_bootswatch = f"@import '{sass_dir.value}/wvc-theme/{theme}/bootswatch';"
-
-
+ scss_bootswatch = (
+ f"@import '{sass_dir.value}/wvc-theme/{theme}/bootswatch';"
+ )
try:
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,
@@ -82,7 +88,10 @@ def appsettings(request):
setting.value = request.POST.get(setting.key, "")
setting.save()
- msg = _("%(setting)s is changed. Now: %(value)s") % {"setting": setting.name, "value": setting.value}
+ msg = _("%(setting)s is changed. Now: %(value)s") % {
+ "setting": setting.name,
+ "value": setting.value,
+ }
messages.success(request, msg)
except Exception as err:
msg = err
diff --git a/computes/api/serializers.py b/computes/api/serializers.py
index d7cd096..e79ab05 100644
--- a/computes/api/serializers.py
+++ b/computes/api/serializers.py
@@ -1,4 +1,3 @@
-
from rest_framework import serializers
from computes.models import Compute
from vrtManager.connection import (
@@ -10,18 +9,17 @@ from vrtManager.connection import (
class ComputeSerializer(serializers.ModelSerializer):
- # Use for the input.
- password = serializers.CharField(style={'input_type': 'password'})
+ # Use for the input.
+ password = serializers.CharField(style={"input_type": "password"})
# Use a radio input instead of a select input.
conn_types = (
- (CONN_SSH, 'SSH'),
- (CONN_TCP, 'TCP'),
- (CONN_TLS, 'TLS'),
- (CONN_SOCKET, 'SOCK'),
+ (CONN_SSH, "SSH"),
+ (CONN_TCP, "TCP"),
+ (CONN_TLS, "TLS"),
+ (CONN_SOCKET, "SOCK"),
)
type = serializers.ChoiceField(choices=conn_types)
-
class Meta:
model = Compute
- fields = ['id', 'name', 'hostname', 'login', 'password', 'type', 'details']
+ fields = ["id", "name", "hostname", "login", "password", "type", "details"]
diff --git a/computes/api/viewsets.py b/computes/api/viewsets.py
index c7d8acc..df960cb 100644
--- a/computes/api/viewsets.py
+++ b/computes/api/viewsets.py
@@ -11,13 +11,13 @@ class ComputeViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows computes to be viewed or edited.
"""
- queryset = Compute.objects.all().order_by('name')
+
+ queryset = Compute.objects.all().order_by("name")
serializer_class = ComputeSerializer
permission_classes = [permissions.IsAuthenticated]
class ComputeArchitecturesView(viewsets.ViewSet):
-
def list(self, request, compute_pk=None):
"""
Return a list of supported host architectures.
@@ -43,7 +43,6 @@ class ComputeArchitecturesView(viewsets.ViewSet):
class ComputeMachinesView(viewsets.ViewSet):
-
def list(self, request, compute_pk=None, archs_pk=None):
"""
Return a list of supported host architectures.
diff --git a/computes/forms.py b/computes/forms.py
index 6927272..1128695 100644
--- a/computes/forms.py
+++ b/computes/forms.py
@@ -13,8 +13,8 @@ class TcpComputeForm(forms.ModelForm):
class Meta:
model = Compute
- widgets = {'password': forms.PasswordInput()}
- fields = '__all__'
+ widgets = {"password": forms.PasswordInput()}
+ fields = "__all__"
class SshComputeForm(forms.ModelForm):
@@ -23,7 +23,7 @@ class SshComputeForm(forms.ModelForm):
class Meta:
model = Compute
- exclude = ['password']
+ exclude = ["password"]
class TlsComputeForm(forms.ModelForm):
@@ -32,14 +32,14 @@ class TlsComputeForm(forms.ModelForm):
class Meta:
model = Compute
- widgets = {'password': forms.PasswordInput()}
- fields = '__all__'
+ widgets = {"password": forms.PasswordInput()}
+ fields = "__all__"
class SocketComputeForm(forms.ModelForm):
- hostname = forms.CharField(widget=forms.HiddenInput, initial='localhost')
+ hostname = forms.CharField(widget=forms.HiddenInput, initial="localhost")
type = forms.IntegerField(widget=forms.HiddenInput, initial=CONN_SOCKET)
class Meta:
model = Compute
- fields = ['name', 'details', 'hostname', 'type']
+ fields = ["name", "details", "hostname", "type"]
diff --git a/computes/models.py b/computes/models.py
index b1c3cd1..f81eafa 100644
--- a/computes/models.py
+++ b/computes/models.py
@@ -8,11 +8,11 @@ from vrtManager.hostdetails import wvmHostDetails
class Compute(Model):
- name = CharField(_('name'), max_length=64, unique=True)
- hostname = CharField(_('hostname'), max_length=64)
- login = CharField(_('login'), max_length=20)
- password = CharField(_('password'), max_length=14, blank=True, null=True)
- details = CharField(_('details'), max_length=64, null=True, blank=True)
+ name = CharField(_("name"), max_length=64, unique=True)
+ hostname = CharField(_("hostname"), max_length=64)
+ login = CharField(_("login"), max_length=20)
+ password = CharField(_("password"), max_length=14, blank=True, null=True)
+ details = CharField(_("details"), max_length=64, null=True, blank=True)
type = IntegerField()
@cached_property
@@ -55,7 +55,7 @@ class Compute(Model):
@cached_property
def ram_usage(self):
- return self.proxy.get_memory_usage()['percent']
+ return self.proxy.get_memory_usage()["percent"]
def __str__(self):
return self.name
diff --git a/computes/tests.py b/computes/tests.py
index 7b94825..5f5cd67 100644
--- a/computes/tests.py
+++ b/computes/tests.py
@@ -7,115 +7,121 @@ from .models import Compute
class ComputesTestCase(TestCase):
def setUp(self):
- self.client.login(username='admin', password='admin')
+ self.client.login(username="admin", password="admin")
Compute(
- name='local',
- hostname='localhost',
- login='',
- password='',
- details='local',
+ name="local",
+ hostname="localhost",
+ login="",
+ password="",
+ details="local",
type=4,
).save()
def test_index(self):
- response = self.client.get(reverse('computes'))
+ response = self.client.get(reverse("computes"))
self.assertEqual(response.status_code, 200)
def test_create_update_delete(self):
- response = self.client.get(reverse('add_socket_host'))
+ response = self.client.get(reverse("add_socket_host"))
self.assertEqual(response.status_code, 200)
response = self.client.post(
- reverse('add_socket_host'),
+ reverse("add_socket_host"),
{
- 'name': 'l1',
- 'details': 'Created',
- 'hostname': 'localhost',
- 'type': 4,
+ "name": "l1",
+ "details": "Created",
+ "hostname": "localhost",
+ "type": 4,
},
)
- self.assertRedirects(response, reverse('computes'))
+ self.assertRedirects(response, reverse("computes"))
compute = Compute.objects.get(pk=2)
- self.assertEqual(compute.name, 'l1')
- self.assertEqual(compute.details, 'Created')
+ self.assertEqual(compute.name, "l1")
+ self.assertEqual(compute.details, "Created")
- response = self.client.get(reverse('compute_update', args=[2]))
+ response = self.client.get(reverse("compute_update", args=[2]))
self.assertEqual(response.status_code, 200)
response = self.client.post(
- reverse('compute_update', args=[2]),
+ reverse("compute_update", args=[2]),
{
- 'name': 'l2',
- 'details': 'Updated',
- 'hostname': 'localhost',
- 'type': 4,
+ "name": "l2",
+ "details": "Updated",
+ "hostname": "localhost",
+ "type": 4,
},
)
- self.assertRedirects(response, reverse('computes'))
+ self.assertRedirects(response, reverse("computes"))
compute = Compute.objects.get(pk=2)
- self.assertEqual(compute.name, 'l2')
- self.assertEqual(compute.details, 'Updated')
+ self.assertEqual(compute.name, "l2")
+ self.assertEqual(compute.details, "Updated")
- response = self.client.get(reverse('compute_delete', args=[2]))
+ response = self.client.get(reverse("compute_delete", args=[2]))
self.assertEqual(response.status_code, 200)
- response = self.client.post(reverse('compute_delete', args=[2]))
- self.assertRedirects(response, reverse('computes'))
+ response = self.client.post(reverse("compute_delete", args=[2]))
+ self.assertRedirects(response, reverse("computes"))
with self.assertRaises(ObjectDoesNotExist):
Compute.objects.get(id=2)
def test_overview(self):
- response = self.client.get(reverse('overview', args=[1]))
+ response = self.client.get(reverse("overview", args=[1]))
self.assertEqual(response.status_code, 200)
def test_graph(self):
- response = self.client.get(reverse('compute_graph', args=[1]))
+ response = self.client.get(reverse("compute_graph", args=[1]))
self.assertEqual(response.status_code, 200)
def test_instances(self):
- response = self.client.get(reverse('instances', args=[1]))
+ response = self.client.get(reverse("instances", args=[1]))
self.assertEqual(response.status_code, 200)
def test_storages(self):
- response = self.client.get(reverse('storages', args=[1]))
+ response = self.client.get(reverse("storages", args=[1]))
self.assertEqual(response.status_code, 200)
def test_storage(self):
pass
def test_default_storage_volumes(self):
- response = self.client.get(reverse('volumes', kwargs={'compute_id': 1, 'pool': 'default'}))
+ response = self.client.get(
+ reverse("volumes", kwargs={"compute_id": 1, "pool": "default"})
+ )
self.assertEqual(response.status_code, 200)
def test_default_storage(self):
- response = self.client.get(reverse('storage', kwargs={'compute_id': 1, 'pool': 'default'}))
+ response = self.client.get(
+ reverse("storage", kwargs={"compute_id": 1, "pool": "default"})
+ )
self.assertEqual(response.status_code, 200)
def test_networks(self):
- response = self.client.get(reverse('networks', args=[1]))
+ response = self.client.get(reverse("networks", args=[1]))
self.assertEqual(response.status_code, 200)
def test_default_network(self):
- response = self.client.get(reverse('network', kwargs={'compute_id': 1, 'pool': 'default'}))
+ response = self.client.get(
+ reverse("network", kwargs={"compute_id": 1, "pool": "default"})
+ )
self.assertEqual(response.status_code, 200)
def test_interfaces(self):
- response = self.client.get(reverse('interfaces', args=[1]))
+ response = self.client.get(reverse("interfaces", args=[1]))
self.assertEqual(response.status_code, 200)
# TODO: add test for single interface
def test_nwfilters(self):
- response = self.client.get(reverse('nwfilters', args=[1]))
+ response = self.client.get(reverse("nwfilters", args=[1]))
self.assertEqual(response.status_code, 200)
# TODO: add test for single nwfilter
def test_secrets(self):
- response = self.client.get(reverse('virtsecrets', args=[1]))
+ response = self.client.get(reverse("virtsecrets", args=[1]))
self.assertEqual(response.status_code, 200)
# def test_create_instance_select_type(self):
@@ -125,19 +131,29 @@ class ComputesTestCase(TestCase):
# TODO: create_instance
def test_machines(self):
- response = self.client.get(reverse('machines', kwargs={'compute_id': 1, 'arch': 'x86_64'}))
+ response = self.client.get(
+ reverse("machines", kwargs={"compute_id": 1, "arch": "x86_64"})
+ )
self.assertEqual(response.status_code, 200)
def test_compute_disk_buses(self):
response = self.client.get(
- reverse('buses', kwargs={
- 'compute_id': 1,
- 'arch': 'x86_64',
- 'machine': 'pc',
- 'disk': 'disk',
- }))
+ reverse(
+ "buses",
+ kwargs={
+ "compute_id": 1,
+ "arch": "x86_64",
+ "machine": "pc",
+ "disk": "disk",
+ },
+ )
+ )
self.assertEqual(response.status_code, 200)
def test_dom_capabilities(self):
- response = self.client.get(reverse('domcaps', kwargs={'compute_id': 1, 'arch': 'x86_64', 'machine': 'pc'}))
+ response = self.client.get(
+ reverse(
+ "domcaps", kwargs={"compute_id": 1, "arch": "x86_64", "machine": "pc"}
+ )
+ )
self.assertEqual(response.status_code, 200)
diff --git a/computes/urls.py b/computes/urls.py
index 8938107..586f73f 100644
--- a/computes/urls.py
+++ b/computes/urls.py
@@ -9,36 +9,71 @@ from storages.views import create_volume, get_volumes, storage, storages
from . import forms, views
urlpatterns = [
- path('', views.computes, name='computes'),
- path('add_tcp_host/', views.compute_create, {'FormClass': forms.TcpComputeForm}, name='add_tcp_host'),
- path('add_ssh_host/', views.compute_create, {'FormClass': forms.SshComputeForm}, name='add_ssh_host'),
- path('add_tls_host/', views.compute_create, {'FormClass': forms.TlsComputeForm}, name='add_tls_host'),
- path('add_socket_host/', views.compute_create, {'FormClass': forms.SocketComputeForm}, name='add_socket_host'),
+ path("", views.computes, name="computes"),
path(
- '/',
- include([
- path('', views.overview, name='overview'),
- path('update/', views.compute_update, name='compute_update'),
- path('delete/', views.compute_delete, name='compute_delete'),
- path('statistics', views.compute_graph, name='compute_graph'),
- path('instances/', views.instances, name='instances'),
- path('storages/', storages, name='storages'),
- path('storage//volumes/', get_volumes, name='volumes'),
- path('storage//', storage, name='storage'),
- path('storage//create_volume/', create_volume, name='create_volume'),
- path('networks/', networks, name='networks'),
- path('network//', network, name='network'),
- path('interfaces/', interfaces, name='interfaces'),
- path('interface//', interface, name='interface'),
- path('nwfilters/', nwfilters, name='nwfilters'),
- path('nwfilter//', nwfilter, name='nwfilter'),
- path('virtsecrets/', secrets, name='virtsecrets'),
- path('archs//machines/', views.get_compute_machine_types, name='machines'),
- path(
- 'archs//machines//disks//buses/',
- views.get_compute_disk_buses,
- name='buses',
- ),
- path('archs//machines//capabilities/', views.get_dom_capabilities, name='domcaps'),
- ])),
+ "add_tcp_host/",
+ views.compute_create,
+ {"FormClass": forms.TcpComputeForm},
+ name="add_tcp_host",
+ ),
+ path(
+ "add_ssh_host/",
+ views.compute_create,
+ {"FormClass": forms.SshComputeForm},
+ name="add_ssh_host",
+ ),
+ path(
+ "add_tls_host/",
+ views.compute_create,
+ {"FormClass": forms.TlsComputeForm},
+ name="add_tls_host",
+ ),
+ path(
+ "add_socket_host/",
+ views.compute_create,
+ {"FormClass": forms.SocketComputeForm},
+ name="add_socket_host",
+ ),
+ path(
+ "/",
+ include(
+ [
+ path("", views.overview, name="overview"),
+ path("update/", views.compute_update, name="compute_update"),
+ path("delete/", views.compute_delete, name="compute_delete"),
+ path("statistics", views.compute_graph, name="compute_graph"),
+ path("instances/", views.instances, name="instances"),
+ path("storages/", storages, name="storages"),
+ path("storage//volumes/", get_volumes, name="volumes"),
+ path("storage//", storage, name="storage"),
+ path(
+ "storage//create_volume/",
+ create_volume,
+ name="create_volume",
+ ),
+ path("networks/", networks, name="networks"),
+ path("network//", network, name="network"),
+ path("interfaces/", interfaces, name="interfaces"),
+ path("interface//", interface, name="interface"),
+ path("nwfilters/", nwfilters, name="nwfilters"),
+ path("nwfilter//", nwfilter, name="nwfilter"),
+ path("virtsecrets/", secrets, name="virtsecrets"),
+ path(
+ "archs//machines/",
+ views.get_compute_machine_types,
+ name="machines",
+ ),
+ path(
+ "archs//machines//disks//buses/",
+ views.get_compute_disk_buses,
+ name="buses",
+ ),
+ path(
+ "archs//machines//capabilities/",
+ views.get_dom_capabilities,
+ name="domcaps",
+ ),
+ ]
+ ),
+ ),
]
diff --git a/computes/utils.py b/computes/utils.py
index 05feb03..881f5eb 100644
--- a/computes/utils.py
+++ b/computes/utils.py
@@ -9,7 +9,7 @@ def refresh_instance_database(compute):
Instance.objects.filter(compute=compute).exclude(name__in=domain_names).delete()
Instance.objects.filter(compute=compute).exclude(uuid__in=domain_uuids).delete()
# Create instances that're on host but not in DB
- names = Instance.objects.filter(compute=compute).values_list('name', flat=True)
+ names = Instance.objects.filter(compute=compute).values_list("name", flat=True)
for domain in domains:
if domain.name() not in names:
- Instance(compute=compute, name=domain.name(), uuid=domain.UUIDString()).save()
+ Instance( compute=compute, name=domain.name(), uuid=domain.UUIDString()).save()
diff --git a/computes/validators.py b/computes/validators.py
index 64458fc..dbb79ee 100644
--- a/computes/validators.py
+++ b/computes/validators.py
@@ -3,9 +3,9 @@ import re
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
-have_symbol = re.compile('[^a-zA-Z0-9._-]+')
-wrong_ip = re.compile('^0.|^255.')
-wrong_name = re.compile('[^a-zA-Z0-9._-]+')
+have_symbol = re.compile("[^a-zA-Z0-9._-]+")
+wrong_ip = re.compile("^0.|^255.")
+wrong_name = re.compile("[^a-zA-Z0-9._-]+")
def validate_hostname(value):
@@ -13,12 +13,14 @@ def validate_hostname(value):
wip = wrong_ip.match(value)
if sym:
- raise ValidationError(_('Hostname must contain only numbers, or the domain name separated by "."'))
+ raise ValidationError(
+ _('Hostname must contain only numbers, or the domain name separated by "."')
+ )
elif wip:
- raise ValidationError(_('Wrong IP address'))
+ raise ValidationError(_("Wrong IP address"))
def validate_name(value):
- have_symbol = wrong_name.match('[^a-zA-Z0-9._-]+')
+ have_symbol = wrong_name.match("[^a-zA-Z0-9._-]+")
if have_symbol:
- raise ValidationError(_('The hostname must not contain any special characters'))
+ raise ValidationError(_("The hostname must not contain any special characters"))
diff --git a/computes/views.py b/computes/views.py
index 7d9184b..0883b54 100644
--- a/computes/views.py
+++ b/computes/views.py
@@ -7,7 +7,12 @@ from django.utils import timezone
from libvirt import libvirtError
from admin.decorators import superuser_only
-from computes.forms import SocketComputeForm, SshComputeForm, TcpComputeForm, TlsComputeForm
+from computes.forms import (
+ SocketComputeForm,
+ SshComputeForm,
+ TcpComputeForm,
+ TlsComputeForm,
+)
from computes.models import Compute
from instances.models import Instance
from vrtManager.connection import (
@@ -39,7 +44,8 @@ def computes(request):
def overview(request, compute_id):
compute = get_object_or_404(Compute, pk=compute_id)
status = (
- "true" if connection_manager.host_is_up(compute.type, compute.hostname) is True else "false"
+ "true"
+ if connection_manager.host_is_up(compute.type, compute.hostname) is True else "false"
)
conn = wvmHostDetails(
@@ -48,7 +54,14 @@ def overview(request, compute_id):
compute.password,
compute.type,
)
- hostname, host_arch, host_memory, logical_cpu, model_cpu, uri_conn = conn.get_node_info()
+ (
+ hostname,
+ host_arch,
+ host_memory,
+ logical_cpu,
+ model_cpu,
+ uri_conn,
+ ) = conn.get_node_info()
hypervisor = conn.get_hypervisors_domain_types()
mem_usage = conn.get_memory_usage()
emulator = conn.get_emulator(host_arch)
@@ -64,9 +77,15 @@ def instances(request, compute_id):
compute = get_object_or_404(Compute, pk=compute_id)
utils.refresh_instance_database(compute)
- instances = Instance.objects.filter(compute=compute).prefetch_related("userinstance_set")
+ instances = Instance.objects.filter(compute=compute).prefetch_related(
+ "userinstance_set"
+ )
- return render(request, "computes/instances.html", {"compute": compute, "instances": instances})
+ return render(
+ request,
+ "computes/instances.html",
+ {"compute": compute, "instances": instances}
+ )
@superuser_only
diff --git a/conf/requirements.txt b/conf/requirements.txt
index d2bf6a7..eac1d67 100644
--- a/conf/requirements.txt
+++ b/conf/requirements.txt
@@ -1,12 +1,12 @@
-Django==3.2.15
+Django==3.2.16
django_bootstrap5==22.1
django-icons==22.1
-django-login-required-middleware==0.8
+django-login-required-middleware==0.9.0
django-otp==1.1.3
-django-qr-code==2.3.0
+django-qr-code==3.1.1
gunicorn==20.1.0
libsass==0.21.0
-libvirt-python==8.6.0
+libvirt-python==8.8.0
lxml==4.9.1
qrcode==7.3.1
rwlock==0.0.7
@@ -16,7 +16,7 @@ ldap3==2.9.1
python-engineio==4.3.4
python-socketio==5.7.1
eventlet==0.33.1
-djangorestframework==3.13.1
+djangorestframework==3.14.0
drf-nested-routers==0.93.4
-drf-yasg==1.21.3
+drf-yasg==1.21.4
markdown==3.4.1
diff --git a/console/novncd b/console/novncd
index 59ff686..08cb51d 100755
--- a/console/novncd
+++ b/console/novncd
@@ -6,9 +6,9 @@ import logging
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')
-CERT = DIR_PATH + '/cert.pem'
+ROOT_PATH = os.path.abspath(os.path.join(DIR_PATH, "..", ""))
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "webvirtcloud.settings")
+CERT = DIR_PATH + "/cert.pem"
if ROOT_PATH not in sys.path:
sys.path.append(ROOT_PATH)
@@ -17,7 +17,8 @@ django.setup()
import re
import socket
-#from six.moves import http_cookies as Cookie
+
+# from six.moves import http_cookies as Cookie
from http import cookies as Cookie
from webvirtcloud.settings import WS_PORT, WS_HOST, WS_CERT
from vrtManager.connection import CONN_SSH, CONN_SOCKET
@@ -26,40 +27,40 @@ from optparse import OptionParser
parser = OptionParser()
-parser.add_option("-v",
- "--verbose",
- dest="verbose",
- action="store_true",
- help="Verbose mode",
- default=False)
+parser.add_option(
+ "-v",
+ "--verbose",
+ dest="verbose",
+ action="store_true",
+ help="Verbose mode",
+ default=False,
+)
-parser.add_option("-d",
- "--debug",
- dest="debug",
- action="store_true",
- help="Debug mode",
- default=False)
+parser.add_option(
+ "-d", "--debug", dest="debug", action="store_true", help="Debug mode", default=False
+)
-parser.add_option("-H",
- "--host",
- dest="host",
- action="store",
- help="Listen host",
- default=WS_HOST)
+parser.add_option(
+ "-H", "--host", dest="host", action="store", help="Listen host", default=WS_HOST
+)
-parser.add_option("-p",
- "--port",
- dest="port",
- action="store",
- help="Listen port",
- default=WS_PORT or 6080)
+parser.add_option(
+ "-p",
+ "--port",
+ dest="port",
+ action="store",
+ help="Listen port",
+ default=WS_PORT or 6080,
+)
-parser.add_option("-c",
- "--cert",
- dest="cert",
- action="store",
- help="Certificate file path",
- default=WS_CERT or CERT)
+parser.add_option(
+ "-c",
+ "--cert",
+ dest="cert",
+ action="store",
+ help="Certificate file path",
+ default=WS_CERT or CERT,
+)
(options, args) = parser.parse_args()
@@ -74,6 +75,7 @@ else:
try:
from websockify import WebSocketProxy
+
try:
from websockify import ProxyRequestHandler
except ImportError:
@@ -84,7 +86,7 @@ except ImportError:
try:
from novnc.wsproxy import WebSocketProxy
except ImportError:
- print('Unable to import a websockify implementation,\n please install one')
+ print("Unable to import a websockify implementation,\n please install one")
sys.exit(1)
else:
USE_HANDLER = False
@@ -95,18 +97,20 @@ def get_connection_infos(token):
from vrtManager.instance import wvmInstance
try:
- temptoken = token.split('-', 1)
+ temptoken = token.split("-", 1)
host = int(temptoken[0])
uuid = temptoken[1]
instance = Instance.objects.get(compute_id=host, uuid=uuid)
- conn = wvmInstance(instance.compute.hostname,
- instance.compute.login,
- instance.compute.password,
- instance.compute.type,
- instance.name)
- if instance.compute.hostname.count(':'):
- connhost = instance.compute.hostname.split(':')[0]
- connport = instance.compute.hostname.split(':')[1]
+ conn = wvmInstance(
+ instance.compute.hostname,
+ instance.compute.login,
+ instance.compute.password,
+ instance.compute.type,
+ instance.name,
+ )
+ if instance.compute.hostname.count(":"):
+ connhost = instance.compute.hostname.split(":")[0]
+ connport = instance.compute.hostname.split(":")[1]
else:
connhost = instance.compute.hostname
connport = 22
@@ -117,10 +121,18 @@ def get_connection_infos(token):
console_socket = conn.get_console_socket()
except Exception as e:
logging.error(
- 'Fail to retrieve console connection infos for token %s : %s' % (token, e))
+ "Fail to retrieve console connection infos for token %s : %s" % (token, e)
+ )
raise
- return (connhost, connport, connuser, conntype, console_host,
- console_port, console_socket)
+ return (
+ connhost,
+ connport,
+ connuser,
+ conntype,
+ console_host,
+ console_port,
+ console_socket,
+ )
class CompatibilityMixIn(object):
@@ -128,25 +140,31 @@ class CompatibilityMixIn(object):
# 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')
+ hcookie = self.headers.get("cookie")
if hcookie:
cookie = Cookie.SimpleCookie()
- for hcookie_part in hcookie.split(';'):
+ 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')
+ self.msg("Found malformed cookie")
else:
- if 'token' in cookie:
- token = cookie['token'].value
+ if "token" in cookie:
+ token = cookie["token"].value
-
- (connhost, connport, connuser, conntype, console_host, console_port,
- console_socket) = get_connection_infos(token)
+ (
+ connhost,
+ connport,
+ connuser,
+ conntype,
+ console_host,
+ console_port,
+ console_socket,
+ ) = get_connection_infos(token)
cnx_debug_msg = "Connection infos :\n"
cnx_debug_msg += "- connhost : '%s'\n" % connhost
@@ -160,14 +178,16 @@ class CompatibilityMixIn(object):
if console_socket and conntype == CONN_SOCKET:
# Local socket on local host
- self.msg('Try to open local socket %s' % console_socket)
+ self.msg("Try to open local socket %s" % console_socket)
tsock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
tsock.connect(console_socket)
- elif console_socket or re.match('^127\.', console_host):
+ elif console_socket or re.match("^127\.", console_host):
# Need tunnel to physical host
if conntype != CONN_SSH:
- self.msg("Need a tunnel to access console but can't mount " +
- "one because it's not a SSH host")
+ self.msg(
+ "Need a tunnel to access console but can't mount "
+ + "one because it's not a SSH host"
+ )
raise Exception(self.msg)
try:
# generate a string with all placeholders to avoid TypeErrors
@@ -175,10 +195,25 @@ class CompatibilityMixIn(object):
# https://github.com/retspen/webvirtmgr/pull/497
error_msg = "Try to open tunnel on %s@%s:%s on console %s:%s "
error_msg += "(or socket %s)"
- self.msg(error_msg % (connuser, connhost, connport,
- console_host, console_port, console_socket))
- tunnel = SSHTunnels(connhost, connuser, connport,
- console_host, console_port, console_socket)
+ self.msg(
+ error_msg
+ % (
+ connuser,
+ connhost,
+ connport,
+ console_host,
+ console_port,
+ console_socket,
+ )
+ )
+ tunnel = SSHTunnels(
+ connhost,
+ connuser,
+ connport,
+ console_host,
+ console_port,
+ console_socket,
+ )
fd = tunnel.open_new()
tunnel.unlock()
tsock = socket.fromfd(fd, socket.AF_INET, socket.SOCK_STREAM)
@@ -202,15 +237,18 @@ class CompatibilityMixIn(object):
except Exception:
if tunnel:
self.vmsg(
- "%s:%s (via %s@%s:%s) : Websocket client or Target closed" %
- (console_host, console_port, connuser, connhost, connport))
+ "%s:%s (via %s@%s:%s) : Websocket client or Target closed"
+ % (console_host, console_port, connuser, connhost, connport)
+ )
if tsock:
tsock.shutdown(socket.SHUT_RDWR)
tsock.close()
tunnel.close_all()
raise
+
if USE_HANDLER:
+
class NovaProxyRequestHandler(ProxyRequestHandler, CompatibilityMixIn):
def msg(self, *args, **kwargs):
self.log_message(*args, **kwargs)
@@ -228,9 +266,10 @@ if USE_HANDLER:
socket_factory = self.server.socket
self._new_client(daemon, socket_factory)
-else:
- class NovaWebSocketProxy(WebSocketProxy, CompatibilityMixIn):
+else:
+
+ class NovaWebSocketProxy(WebSocketProxy, CompatibilityMixIn):
def new_client(self):
"""
Called after a new WebSocket connection has been established.
@@ -241,39 +280,44 @@ else:
self._new_client(daemon, socket_factory)
-if __name__ == '__main__':
+
+if __name__ == "__main__":
if USE_HANDLER:
# Create the WebSocketProxy with NovaProxyRequestHandler handler
- server = WebSocketProxy(RequestHandlerClass=NovaProxyRequestHandler,
- listen_host=options.host,
- listen_port=options.port,
- source_is_ipv6=False,
- verbose=options.verbose,
- cert=options.cert,
- key=None,
- ssl_only=False,
- daemon=False,
- record=False,
- web=False,
- traffic=False,
- target_host='ignore',
- target_port='ignore',
- wrap_mode='exit',
- wrap_cmd=None)
+ server = WebSocketProxy(
+ RequestHandlerClass=NovaProxyRequestHandler,
+ listen_host=options.host,
+ listen_port=options.port,
+ source_is_ipv6=False,
+ verbose=options.verbose,
+ cert=options.cert,
+ key=None,
+ ssl_only=False,
+ daemon=False,
+ record=False,
+ web=False,
+ traffic=False,
+ target_host="ignore",
+ target_port="ignore",
+ wrap_mode="exit",
+ wrap_cmd=None,
+ )
else:
# Create the NovaWebSockets proxy
- server = NovaWebSocketProxy(listen_host=options.host,
- listen_port=options.port,
- source_is_ipv6=False,
- verbose=options.verbose,
- cert=options.cert,
- key=None,
- ssl_only=False,
- daemon=False,
- record=False,
- web=False,
- target_host='ignore',
- target_port='ignore',
- wrap_mode='exit',
- wrap_cmd=None)
+ server = NovaWebSocketProxy(
+ listen_host=options.host,
+ listen_port=options.port,
+ source_is_ipv6=False,
+ verbose=options.verbose,
+ cert=options.cert,
+ key=None,
+ ssl_only=False,
+ daemon=False,
+ record=False,
+ web=False,
+ target_host="ignore",
+ target_port="ignore",
+ wrap_mode="exit",
+ wrap_cmd=None,
+ )
server.start_server()
diff --git a/console/socketiod b/console/socketiod
index 7057d9a..dbd38bc 100755
--- a/console/socketiod
+++ b/console/socketiod
@@ -5,9 +5,9 @@ import logging
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')
-CERT = DIR_PATH + '/cert.pem'
+ROOT_PATH = os.path.abspath(os.path.join(DIR_PATH, "..", ""))
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "webvirtcloud.settings")
+CERT = DIR_PATH + "/cert.pem"
if ROOT_PATH not in sys.path:
sys.path.append(ROOT_PATH)
@@ -32,7 +32,7 @@ import tty
import termios
import libvirt
-#from six.moves import http_cookies as Cookie
+# from six.moves import http_cookies as Cookie
from http import cookies as Cookie
from webvirtcloud.settings import SOCKETIO_PORT, SOCKETIO_HOST
from vrtManager.connection import CONN_SSH, CONN_SOCKET
@@ -40,33 +40,36 @@ from optparse import OptionParser
parser = OptionParser()
-parser.add_option("-v",
- "--verbose",
- dest="verbose",
- action="store_true",
- help="Verbose mode",
- default=False)
+parser.add_option(
+ "-v",
+ "--verbose",
+ dest="verbose",
+ action="store_true",
+ help="Verbose mode",
+ default=False,
+)
-parser.add_option("-d",
- "--debug",
- dest="debug",
- action="store_true",
- help="Debug mode",
- default=False)
+parser.add_option(
+ "-d", "--debug", dest="debug", action="store_true", help="Debug mode", default=False
+)
-parser.add_option("-H",
- "--host",
- dest="host",
- action="store",
- help="Listen host",
- default=SOCKETIO_HOST)
+parser.add_option(
+ "-H",
+ "--host",
+ dest="host",
+ action="store",
+ help="Listen host",
+ default=SOCKETIO_HOST,
+)
-parser.add_option("-p",
- "--port",
- dest="port",
- action="store",
- help="Listen port",
- default=SOCKETIO_PORT or 6081)
+parser.add_option(
+ "-p",
+ "--port",
+ dest="port",
+ action="store",
+ help="Listen port",
+ default=SOCKETIO_PORT or 6081,
+)
(options, args) = parser.parse_args()
@@ -85,26 +88,31 @@ sio = socketio.Server(async_mode=async_mode, cors_allowed_origins=[])
fd = None
child_pid = None
+
def get_connection_infos(token):
from instances.models import Instance
from vrtManager.instance import wvmInstance
try:
- temptoken = token.split('-', 1)
+ temptoken = token.split("-", 1)
host = int(temptoken[0])
uuid = temptoken[1]
instance = Instance.objects.get(compute_id=host, uuid=uuid)
- conn = wvmInstance(instance.compute.hostname,
- instance.compute.login,
- instance.compute.password,
- instance.compute.type,
- instance.name)
+ conn = wvmInstance(
+ instance.compute.hostname,
+ instance.compute.login,
+ instance.compute.password,
+ instance.compute.type,
+ instance.name,
+ )
except Exception as e:
logging.error(
- 'Fail to retrieve console connection infos for token %s : %s' % (token, e))
+ "Fail to retrieve console connection infos for token %s : %s" % (token, e)
+ )
raise
return (instance, conn)
+
def set_winsize(fd, row, col, xpix=0, ypix=0):
winsize = struct.pack("HHHH", row, col, xpix, ypix)
fcntl.ioctl(fd, termios.TIOCSWINSZ, winsize)
@@ -123,41 +131,44 @@ def read_and_forward_pty_output():
sio.emit("pty_output", {"output": output})
else:
return
-
+
@sio.event
-def resize(sid, message):
+def resize(sid, message):
global fd
if fd:
set_winsize(fd, message["rows"], message["cols"])
+
@sio.event
def pty_input(sid, message):
global fd
if fd:
os.write(fd, message["input"].encode())
+
@sio.event
def disconnect_request(sid):
sio.disconnect(sid)
+
@sio.event
def connect(sid, environ):
global fd
global child_pid
- hcookie = environ.get('HTTP_COOKIE')
+ hcookie = environ.get("HTTP_COOKIE")
if hcookie:
cookie = Cookie.SimpleCookie()
- for hcookie_part in hcookie.split(';'):
+ for hcookie_part in hcookie.split(";"):
hcookie_part = hcookie_part.lstrip()
try:
cookie.load(hcookie_part)
except Cookie.CookieError:
- logging.warn('Found malformed cookie')
+ logging.warn("Found malformed cookie")
else:
- if 'token' in cookie:
- token = cookie['token'].value
+ if "token" in cookie:
+ token = cookie["token"].value
if child_pid:
# already started child process, don't start another
@@ -170,14 +181,15 @@ def connect(sid, environ):
if child_pid == 0:
(instance, conn) = get_connection_infos(token)
- uuid = conn.get_uuid()
+ uuid = conn.get_uuid()
uri = conn.wvm.getURI()
-
- subprocess.run(['conf/daemon/consolecallback', uri, uuid])
+
+ subprocess.run(["conf/daemon/consolecallback", uri, uuid])
else:
# this is the parent process fork.
sio.start_background_task(target=read_and_forward_pty_output)
+
@sio.event
def disconnect(sid):
@@ -185,13 +197,15 @@ def disconnect(sid):
global child_pid
# kill pty process
- os.kill(child_pid,signal.SIGKILL)
+ os.kill(child_pid, signal.SIGKILL)
os.wait()
# reset the variables
fd = None
child_pid = None
+
app = socketio.WSGIApp(sio)
import eventlet
-eventlet.wsgi.server(eventlet.listen((options.host,int(options.port))), app)
+
+eventlet.wsgi.server(eventlet.listen((options.host, int(options.port))), app)
diff --git a/console/sshtunnels.py b/console/sshtunnels.py
index 06f4c9d..7f0376e 100644
--- a/console/sshtunnels.py
+++ b/console/sshtunnels.py
@@ -28,15 +28,19 @@ class _TunnelScheduler(object):
def _handle_queue(self):
while True:
- lock_cb, cb, args, = self._queue.get()
+ (
+ lock_cb,
+ cb,
+ args,
+ ) = self._queue.get()
lock_cb()
cb(*args)
def schedule(self, lock_cb, cb, *args):
if not self._thread:
- self._thread = threading.Thread(name="Tunnel thread",
- target=self._handle_queue,
- args=())
+ self._thread = threading.Thread(
+ name="Tunnel thread", target=self._handle_queue, args=()
+ )
self._thread.daemon = True
if not self._thread.is_alive():
self._thread.start()
@@ -63,8 +67,11 @@ class _Tunnel(object):
return
self._closed = True
- log.debug("Close tunnel PID=%s ERRFD=%s",
- self._pid, self._errfd and self._errfd.fileno() or None)
+ log.debug(
+ "Close tunnel PID=%s ERRFD=%s",
+ self._pid,
+ self._errfd and self._errfd.fileno() or None,
+ )
# Since this is a socket object, the file descriptor is closed
# when it's garbage collected.
@@ -110,8 +117,7 @@ class _Tunnel(object):
self._errfd = errfds[0]
self._errfd.setblocking(0)
- log.debug("Opened tunnel PID=%d ERRFD=%d",
- pid, self._errfd.fileno())
+ log.debug("Opened tunnel PID=%d ERRFD=%d", pid, self._errfd.fileno())
self._pid = pid
@@ -124,7 +130,7 @@ def _make_ssh_command(connhost, connuser, connport, gaddr, gport, gsocket):
argv += ["-p", str(connport)]
if connuser:
- argv += ['-l', connuser]
+ argv += ["-l", connuser]
argv += [connhost]
@@ -151,8 +157,8 @@ def _make_ssh_command(connhost, connuser, connport, gaddr, gport, gsocket):
"""else"""
""" CMD="nc %(nc_params)s";"""
"""fi;"""
- """eval "$CMD";""" %
- {'nc_params': nc_params})
+ """eval "$CMD";""" % {"nc_params": nc_params}
+ )
argv.append("sh -c")
argv.append("'%s'" % nc_cmd)
@@ -166,7 +172,8 @@ class SSHTunnels(object):
def __init__(self, connhost, connuser, connport, gaddr, gport, gsocket):
self._tunnels = []
self._sshcommand = _make_ssh_command(
- connhost, connuser, connport, gaddr, gport, gsocket)
+ connhost, connuser, connport, gaddr, gport, gsocket
+ )
self._locked = False
def open_new(self):
diff --git a/console/views.py b/console/views.py
index 43dd82e..f530df1 100644
--- a/console/views.py
+++ b/console/views.py
@@ -17,7 +17,7 @@ from webvirtcloud.settings import (
WS_PUBLIC_PORT,
SOCKETIO_PUBLIC_HOST,
SOCKETIO_PUBLIC_PORT,
- SOCKETIO_PUBLIC_PATH
+ SOCKETIO_PUBLIC_PATH,
)
@@ -31,32 +31,39 @@ def console(request):
if request.method == "GET":
token = request.GET.get("token", "")
view_type = request.GET.get("view", "lite")
- view_only = request.GET.get(
- "view_only", app_settings.CONSOLE_VIEW_ONLY.lower())
+ view_only = request.GET.get("view_only", app_settings.CONSOLE_VIEW_ONLY.lower())
scale = request.GET.get("scale", app_settings.CONSOLE_SCALE.lower())
resize_session = request.GET.get(
- "resize_session", app_settings.CONSOLE_RESIZE_SESSION.lower())
+ "resize_session", app_settings.CONSOLE_RESIZE_SESSION.lower()
+ )
clip_viewport = request.GET.get(
- "clip_viewport", app_settings.CONSOLE_CLIP_VIEWPORT.lower())
+ "clip_viewport", app_settings.CONSOLE_CLIP_VIEWPORT.lower()
+ )
try:
temptoken = token.split("-", 1)
host = int(temptoken[0])
uuid = temptoken[1]
- if not request.user.is_superuser and not request.user.has_perm("instances.view_instances"):
+ if not request.user.is_superuser and not request.user.has_perm(
+ "instances.view_instances"
+ ):
try:
userInstance = UserInstance.objects.get(
- instance__compute_id=host, instance__uuid=uuid, user__id=request.user.id
+ instance__compute_id=host,
+ instance__uuid=uuid,
+ user__id=request.user.id,
)
instance = Instance.objects.get(compute_id=host, uuid=uuid)
except UserInstance.DoesNotExist:
instance = None
- console_error = _("User does not have permission to access console or host/instance not exist")
+ console_error = _(
+ "User does not have permission to access console or host/instance not exist"
+ )
return HttpResponseServerError(console_error)
else:
instance = Instance.objects.get(compute_id=host, uuid=uuid)
-
+
conn = wvmInstance(
instance.compute.hostname,
instance.compute.login,
@@ -83,7 +90,9 @@ def console(request):
console_page = "console-" + console_type + "-" + view_type + ".html"
response = render(request, console_page, locals())
elif console_type == "pty":
- socketio_host = SOCKETIO_PUBLIC_HOST if SOCKETIO_PUBLIC_HOST else request.get_host()
+ socketio_host = (
+ SOCKETIO_PUBLIC_HOST if SOCKETIO_PUBLIC_HOST else request.get_host()
+ )
socketio_port = SOCKETIO_PUBLIC_PORT if SOCKETIO_PUBLIC_PORT else 6081
socketio_path = SOCKETIO_PUBLIC_PATH if SOCKETIO_PUBLIC_PATH else "/"
@@ -93,9 +102,13 @@ def console(request):
response = render(request, "console-xterm.html", locals())
else:
if console_type is None:
- console_error = _("Fail to get console. Please check the console configuration of your VM.")
+ console_error = _(
+ "Fail to get console. Please check the console configuration of your VM."
+ )
else:
- console_error = _("Console type '%(type)s' has not support") % {"type": console_type}
+ console_error = _("Console type '%(type)s' has not support") % {
+ "type": console_type
+ }
response = render(request, "console-vnc-lite.html", locals())
response.set_cookie("token", token)
diff --git a/datasource/urls.py b/datasource/urls.py
index cba7517..4c8f512 100644
--- a/datasource/urls.py
+++ b/datasource/urls.py
@@ -3,8 +3,14 @@ from django.urls import path
from . import views
urlpatterns = [
- path('openstack/', views.os_index, name='ds_openstack_index'),
- path('openstack//meta_data.json', views.os_metadata_json, name='ds_openstack_metadata'),
- path('openstack//user_data', views.os_userdata, name='ds_openstack_userdata'),
- path('vdi///', views.get_vdi_url, name='vdi_url'),
+ path("openstack/", views.os_index, name="ds_openstack_index"),
+ path(
+ "openstack//meta_data.json",
+ views.os_metadata_json,
+ name="ds_openstack_metadata",
+ ),
+ path(
+ "openstack//user_data", views.os_userdata, name="ds_openstack_userdata"
+ ),
+ path("vdi///", views.get_vdi_url, name="vdi_url"),
]
diff --git a/datasource/views.py b/datasource/views.py
index 1a18ff5..ce74650 100644
--- a/datasource/views.py
+++ b/datasource/views.py
@@ -99,7 +99,13 @@ def get_vdi_url(request, compute_id, vname):
compute = get_object_or_404(Compute, pk=compute_id)
try:
- conn = wvmInstance(compute.hostname, compute.login, compute.password, compute.type, vname)
+ conn = wvmInstance(
+ compute.hostname,
+ compute.login,
+ compute.password,
+ compute.type,
+ vname
+ )
fqdn = get_hostname_by_ip(compute.hostname)
url = f"{conn.get_console_type()}://{fqdn}:{conn.get_console_port()}"
diff --git a/dev/requirements.txt b/dev/requirements.txt
index 0e8ec79..2007735 100644
--- a/dev/requirements.txt
+++ b/dev/requirements.txt
@@ -1,7 +1,8 @@
-r ../conf/requirements.txt
-coverage==6.4.4
-django-debug-toolbar==3.6.0
+coverage==6.5.0
+django-debug-toolbar==3.7.0
pycodestyle==2.9.1
pyflakes==2.5.0
-pylint==2.14.5
+pylint==2.15.3
yapf==0.32.0
+black
\ No newline at end of file
diff --git a/instances/api/serializers.py b/instances/api/serializers.py
index 7e0c0d9..dab19aa 100644
--- a/instances/api/serializers.py
+++ b/instances/api/serializers.py
@@ -4,90 +4,88 @@ from instances.models import Flavor, Instance, MigrateInstance, CreateInstance
class InstanceSerializer(serializers.ModelSerializer):
-
class Meta:
model = Instance
- fields = ['id', 'compute', 'name', 'uuid', 'is_template', 'created', 'drbd']
+ fields = ["id", "compute", "name", "uuid", "is_template", "created", "drbd"]
class InstanceDetailsSerializer(serializers.ModelSerializer):
-
class Meta:
model = Instance
fields = [
- 'id',
- 'compute',
- 'status',
- 'uuid',
- 'name',
- 'title',
- 'description',
- 'is_template',
- 'created',
- 'drbd',
- 'arch',
- 'machine',
- 'vcpu',
- 'memory',
- 'firmware',
- 'nvram',
- 'bootmenu',
- 'boot_order',
- 'disks',
- 'media',
- 'media_iso',
- 'snapshots',
- 'networks',
- 'console_type',
- 'console_port',
- 'console_keymap',
- 'console_listener_address',
- 'video_model',
- 'guest_agent_ready',
- 'autostart']
+ "id",
+ "compute",
+ "status",
+ "uuid",
+ "name",
+ "title",
+ "description",
+ "is_template",
+ "created",
+ "drbd",
+ "arch",
+ "machine",
+ "vcpu",
+ "memory",
+ "firmware",
+ "nvram",
+ "bootmenu",
+ "boot_order",
+ "disks",
+ "media",
+ "media_iso",
+ "snapshots",
+ "networks",
+ "console_type",
+ "console_port",
+ "console_keymap",
+ "console_listener_address",
+ "video_model",
+ "guest_agent_ready",
+ "autostart",
+ ]
class FlavorSerializer(serializers.ModelSerializer):
-
class Meta:
model = Flavor
- fields = ['label', 'memory', 'vcpu', 'disk']
+ fields = ["label", "memory", "vcpu", "disk"]
class CreateInstanceSerializer(serializers.ModelSerializer):
firmware_choices = (
- ('', 'BIOS'),
- #('UEFI', 'UEFI'),
+ ("", "BIOS"),
+ # ('UEFI', 'UEFI'),
)
- firmware = serializers.ChoiceField(choices = firmware_choices)
- graphics = serializers.CharField(initial='vnc')
- video = serializers.CharField(initial='vga')
- storage = serializers.CharField(initial='default')
- cache_mode = serializers.CharField(initial='none')
+ firmware = serializers.ChoiceField(choices=firmware_choices)
+ graphics = serializers.CharField(initial="vnc")
+ video = serializers.CharField(initial="vga")
+ storage = serializers.CharField(initial="default")
+ cache_mode = serializers.CharField(initial="none")
virtio = serializers.BooleanField(initial=True)
qemu_ga = serializers.BooleanField(initial=True)
class Meta:
model = CreateInstance
fields = [
- 'name',
- 'firmware',
- 'vcpu',
- 'vcpu_mode',
- 'memory',
- 'networks',
- 'mac',
- 'nwfilter',
- 'storage',
- 'hdd_size',
- 'cache_mode',
- 'meta_prealloc',
- 'virtio',
- 'qemu_ga',
- 'console_pass',
- 'graphics',
- 'video',
- 'listener_addr'
+ "name",
+ "firmware",
+ "vcpu",
+ "vcpu_mode",
+ "memory",
+ "networks",
+ "mac",
+ "nwfilter",
+ "storage",
+ "hdd_size",
+ "cache_mode",
+ "meta_prealloc",
+ "virtio",
+ "qemu_ga",
+ "console_pass",
+ "graphics",
+ "video",
+ "listener_addr",
]
@@ -95,6 +93,17 @@ class MigrateSerializer(serializers.ModelSerializer):
instance = Instance.objects.all().prefetch_related("userinstance_set")
live = serializers.BooleanField(initial=True)
xml_del = serializers.BooleanField(initial=True)
+
class Meta:
model = MigrateInstance
- fields = ['instance', 'target_compute', 'live', 'xml_del', 'offline', 'autoconverge', 'compress', 'postcopy', 'unsafe']
+ fields = [
+ "instance",
+ "target_compute",
+ "live",
+ "xml_del",
+ "offline",
+ "autoconverge",
+ "compress",
+ "postcopy",
+ "unsafe",
+ ]
diff --git a/instances/api/viewsets.py b/instances/api/viewsets.py
index 1fb06bb..9a42619 100644
--- a/instances/api/viewsets.py
+++ b/instances/api/viewsets.py
@@ -5,7 +5,15 @@ from computes import utils
from instances.models import Flavor, Instance
from instances.views import get_instance
from instances.utils import migrate_instance
-from instances.views import poweron, powercycle, poweroff, force_off, suspend, resume, destroy as instance_destroy
+from instances.views import (
+ poweron,
+ powercycle,
+ poweroff,
+ force_off,
+ suspend,
+ resume,
+ destroy as instance_destroy,
+)
from rest_framework import status, viewsets, permissions
from rest_framework.decorators import action
@@ -14,26 +22,39 @@ from rest_framework.response import Response
from vrtManager import util
from vrtManager.create import wvmCreate
-from .serializers import FlavorSerializer, InstanceSerializer, InstanceDetailsSerializer, MigrateSerializer, CreateInstanceSerializer
+from .serializers import (
+ FlavorSerializer,
+ InstanceSerializer,
+ InstanceDetailsSerializer,
+ MigrateSerializer,
+ CreateInstanceSerializer,
+)
+
class InstancesViewSet(viewsets.ViewSet):
"""
A simple ViewSet for listing or retrieving ALL/Compute Instances.
"""
+
permission_classes = [permissions.IsAuthenticated]
+
def list(self, request):
if request.user.is_superuser or request.user.has_perm("instances.view_instances"):
queryset = Instance.objects.all().prefetch_related("userinstance_set")
else:
queryset = Instance.objects.filter(userinstance__user=request.user).prefetch_related("userinstance_set")
- serializer = InstanceSerializer(queryset, many=True, context={'request': request})
+ serializer = InstanceSerializer(
+ queryset,
+ many=True,
+ context={"request": request}
+ )
return Response(serializer.data)
def retrieve(self, request, pk=None, compute_pk=None):
queryset = get_instance(request.user, pk)
- serializer = InstanceSerializer(queryset, context={'request': request})
+ serializer = InstanceSerializer(queryset, context={"request": request})
return Response(serializer.data)
@@ -42,94 +63,110 @@ class InstanceViewSet(viewsets.ViewSet):
"""
A simple ViewSet for listing or retrieving Compute Instances.
"""
- #serializer_class = CreateInstanceSerializer
+
+ # serializer_class = CreateInstanceSerializer
permission_classes = [permissions.IsAuthenticated]
+
def list(self, request, compute_pk=None):
compute = get_object_or_404(Compute, pk=compute_pk)
utils.refresh_instance_database(compute)
-
- queryset = Instance.objects.filter(compute=compute).prefetch_related("userinstance_set")
- serializer = InstanceSerializer(queryset, many=True, context={'request': request})
-
- return Response(serializer.data)
+ queryset = Instance.objects.filter(compute=compute).prefetch_related("userinstance_set")
+ serializer = InstanceSerializer(
+ queryset,
+ many=True,
+ context={"request": request}
+ )
+
+ return Response(serializer.data)
def retrieve(self, request, pk=None, compute_pk=None):
queryset = get_instance(request.user, pk)
- serializer = InstanceDetailsSerializer(queryset, context={'request': request})
+ serializer = InstanceDetailsSerializer(queryset, context={"request": request})
return Response(serializer.data)
-
def destroy(self, request, pk=None, compute_pk=None):
instance_destroy(request, pk)
- return Response({'status': 'Instance is destroyed'})
+ return Response({"status": "Instance is destroyed"})
- @action(detail=True, methods=['post'])
+ @action(detail=True, methods=["post"])
def poweron(self, request, pk=None):
poweron(request, pk)
- return Response({'status': 'poweron command send'})
-
- @action(detail=True, methods=['post'])
+ return Response({"status": "poweron command send"})
+
+ @action(detail=True, methods=["post"])
def poweroff(self, request, pk=None):
poweroff(request, pk)
- return Response({'status': 'poweroff command send'})
-
- @action(detail=True, methods=['post'])
+ return Response({"status": "poweroff command send"})
+
+ @action(detail=True, methods=["post"])
def powercycle(self, request, pk=None):
powercycle(request, pk)
- return Response({'status': 'powercycle command send'})
-
- @action(detail=True, methods=['post'])
+ return Response({"status": "powercycle command send"})
+
+ @action(detail=True, methods=["post"])
def forceoff(self, request, pk=None):
force_off(request, pk)
- return Response({'status': 'force off command send'})
+ return Response({"status": "force off command send"})
- @action(detail=True, methods=['post'])
+ @action(detail=True, methods=["post"])
def suspend(self, request, pk=None):
suspend(request, pk)
- return Response({'status': 'suspend command send'})
+ return Response({"status": "suspend command send"})
- @action(detail=True, methods=['post'])
+ @action(detail=True, methods=["post"])
def resume(self, request, pk=None):
resume(request, pk)
- return Response({'status': 'resume command send'})
-
+ return Response({"status": "resume command send"})
+
class MigrateViewSet(viewsets.ViewSet):
"""
A viewset for migrating instances.
"""
+
serializer_class = MigrateSerializer
queryset = ""
def create(self, request):
serializer = MigrateSerializer(data=request.data)
if serializer.is_valid():
- instance = serializer.validated_data['instance']
- target_host = serializer.validated_data['target_compute']
- live = serializer.validated_data['live']
- unsafe = serializer.validated_data['unsafe']
- xml_del = serializer.validated_data['xml_del']
- offline = serializer.validated_data['offline']
- autoconverge = serializer.validated_data['autoconverge']
- postcopy = serializer.validated_data['postcopy']
- compress = serializer.validated_data['compress']
+ instance = serializer.validated_data["instance"]
+ target_host = serializer.validated_data["target_compute"]
+ live = serializer.validated_data["live"]
+ unsafe = serializer.validated_data["unsafe"]
+ xml_del = serializer.validated_data["xml_del"]
+ offline = serializer.validated_data["offline"]
+ autoconverge = serializer.validated_data["autoconverge"]
+ postcopy = serializer.validated_data["postcopy"]
+ compress = serializer.validated_data["compress"]
- migrate_instance(target_host, instance, request.user, live, unsafe, xml_del, offline, autoconverge, compress, postcopy)
+ migrate_instance(
+ target_host,
+ instance,
+ request.user,
+ live,
+ unsafe,
+ xml_del,
+ offline,
+ autoconverge,
+ compress,
+ postcopy,
+ )
- return Response({'status': 'instance migrate is started'})
+ return Response({"status": "instance migrate is started"})
else:
- return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
-
+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class FlavorViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows flavor to be viewed.
"""
- queryset = Flavor.objects.all().order_by('id')
+
+ queryset = Flavor.objects.all().order_by("id")
serializer_class = FlavorSerializer
permission_classes = [permissions.IsAuthenticated]
@@ -138,15 +175,15 @@ class CreateInstanceViewSet(viewsets.ViewSet):
"""
A viewset for creating instances.
"""
+
serializer_class = CreateInstanceSerializer
queryset = ""
-
+
def create(self, request, compute_pk=None, arch=None, machine=None):
- serializer = CreateInstanceSerializer(data=request.data,
- context = {'compute_pk': compute_pk,
- 'arch': arch,
- 'machine': machine
- })
+ serializer = CreateInstanceSerializer(
+ data=request.data,
+ context={"compute_pk": compute_pk, "arch": arch, "machine": machine},
+ )
if serializer.is_valid():
volume_list = []
default_bus = app_settings.INSTANCE_VOLUME_DEFAULT_BUS
@@ -166,14 +203,14 @@ class CreateInstanceViewSet(viewsets.ViewSet):
)
path = conn.create_volume(
- serializer.validated_data['storage'],
- serializer.validated_data['name'],
- serializer.validated_data['hdd_size'],
- default_disk_format,
- serializer.validated_data['meta_prealloc'],
- default_disk_owner_uid,
- default_disk_owner_gid,
- )
+ serializer.validated_data["storage"],
+ serializer.validated_data["name"],
+ serializer.validated_data["hdd_size"],
+ default_disk_format,
+ serializer.validated_data["meta_prealloc"],
+ default_disk_owner_uid,
+ default_disk_owner_gid,
+ )
volume = {}
firmware = {}
volume["device"] = "disk"
@@ -189,8 +226,8 @@ class CreateInstanceViewSet(viewsets.ViewSet):
volume_list.append(volume)
- if "UEFI" in serializer.validated_data['firmware']:
- firmware["loader"] = serializer.validated_data['firmware'].split(":")[1].strip()
+ if "UEFI" in serializer.validated_data["firmware"]:
+ firmware["loader"] = (serializer.validated_data["firmware"].split(":")[1].strip())
firmware["secure"] = "no"
firmware["readonly"] = "yes"
firmware["type"] = "pflash"
@@ -199,26 +236,26 @@ class CreateInstanceViewSet(viewsets.ViewSet):
firmware["secure"] = "yes"
ret = conn.create_instance(
- name=serializer.validated_data['name'],
- memory=serializer.validated_data['memory'],
- vcpu=serializer.validated_data['vcpu'],
- vcpu_mode=serializer.validated_data['vcpu_mode'],
+ name=serializer.validated_data["name"],
+ memory=serializer.validated_data["memory"],
+ vcpu=serializer.validated_data["vcpu"],
+ vcpu_mode=serializer.validated_data["vcpu_mode"],
uuid=util.randomUUID(),
arch=arch,
machine=machine,
firmware=firmware,
volumes=volume_list,
- networks=serializer.validated_data['networks'],
- nwfilter=serializer.validated_data['nwfilter'],
- graphics=serializer.validated_data['graphics'],
- virtio=serializer.validated_data['virtio'],
- listener_addr=serializer.validated_data['listener_addr'],
- video=serializer.validated_data['video'],
- console_pass=serializer.validated_data['console_pass'],
- mac=serializer.validated_data['mac'],
- qemu_ga=serializer.validated_data['qemu_ga'],
+ networks=serializer.validated_data["networks"],
+ nwfilter=serializer.validated_data["nwfilter"],
+ graphics=serializer.validated_data["graphics"],
+ virtio=serializer.validated_data["virtio"],
+ listener_addr=serializer.validated_data["listener_addr"],
+ video=serializer.validated_data["video"],
+ console_pass=serializer.validated_data["console_pass"],
+ mac=serializer.validated_data["mac"],
+ qemu_ga=serializer.validated_data["qemu_ga"],
)
msg = f"Instance {serializer.validated_data['name']} is created"
- return Response({'status': msg })
+ return Response({"status": msg})
else:
- return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
\ No newline at end of file
+ return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
diff --git a/instances/apps.py b/instances/apps.py
index 49983ac..a43c6a3 100644
--- a/instances/apps.py
+++ b/instances/apps.py
@@ -3,17 +3,19 @@ from django.db.models.signals import post_migrate
def migrate_can_clone_instances(sender, **kwargs):
- '''
+ """
Migrate can clone instances user attribute to permission
- '''
+ """
from django.contrib.auth.models import Permission, User
- plan = kwargs.get('plan', [])
+ plan = kwargs.get("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()
- permission = Permission.objects.get(codename='clone_instances')
- print('\033[1m* \033[92mMigrating can_clone_instaces user attribute to permission\033[0m')
+ permission = Permission.objects.get(codename="clone_instances")
+ print(
+ "\033[1m* \033[92mMigrating can_clone_instaces user attribute to permission\033[0m"
+ )
for user in users:
if user.userattributes:
if user.userattributes.can_clone_instances:
@@ -22,25 +24,26 @@ def migrate_can_clone_instances(sender, **kwargs):
def apply_passwordless_console(sender, **kwargs):
- '''
+ """
Apply new passwordless_console permission for all users
- '''
+ """
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Permission
+
User = get_user_model()
- plan = kwargs.get('plan', [])
+ 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')
+ 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')
+ permission = Permission.objects.get(codename="passwordless_console")
for user in users:
user.user_permissions.add(permission)
class InstancesConfig(AppConfig):
- name = 'instances'
- verbose_name = 'Instances'
+ name = "instances"
+ verbose_name = "Instances"
def ready(self):
post_migrate.connect(migrate_can_clone_instances, sender=self)
diff --git a/instances/forms.py b/instances/forms.py
index 14e0a9f..d9f09b3 100644
--- a/instances/forms.py
+++ b/instances/forms.py
@@ -12,7 +12,7 @@ from .models import CreateInstance, Flavor
class FlavorForm(forms.ModelForm):
class Meta:
model = Flavor
- fields = '__all__'
+ fields = "__all__"
class ConsoleForm(forms.Form):
@@ -20,17 +20,25 @@ class ConsoleForm(forms.Form):
listen_on = forms.ChoiceField()
generate_password = forms.BooleanField(required=False)
clear_password = forms.BooleanField(required=False)
- password = forms.CharField(widget=forms.PasswordInput(render_value=True), required=False)
+ password = forms.CharField(
+ widget=forms.PasswordInput(render_value=True),
+ required=False
+ )
clear_keymap = forms.BooleanField(required=False)
keymap = forms.ChoiceField(required=False)
def __init__(self, *args, **kwargs):
super(ConsoleForm, self).__init__(*args, **kwargs)
- type_choices = ((c, c) for c in AppSettings.objects.get(key="QEMU_CONSOLE_DEFAULT_TYPE").choices_as_list())
- keymap_choices = [('auto', 'Auto')] + list((c, c) for c in QEMU_KEYMAPS)
- self.fields['type'] = forms.ChoiceField(choices=type_choices)
- self.fields['listen_on'] = forms.ChoiceField(choices=QEMU_CONSOLE_LISTENER_ADDRESSES)
- self.fields['keymap'] = forms.ChoiceField(choices=keymap_choices)
+ type_choices = (
+ (c, c)
+ for c in AppSettings.objects.get(key="QEMU_CONSOLE_DEFAULT_TYPE").choices_as_list()
+ )
+ keymap_choices = [("auto", "Auto")] + list((c, c) for c in QEMU_KEYMAPS)
+ self.fields["type"] = forms.ChoiceField(choices=type_choices)
+ self.fields["listen_on"] = forms.ChoiceField(
+ choices=QEMU_CONSOLE_LISTENER_ADDRESSES
+ )
+ self.fields["keymap"] = forms.ChoiceField(choices=keymap_choices)
class NewVMForm(forms.ModelForm):
@@ -57,12 +65,16 @@ class NewVMForm(forms.ModelForm):
# listener_addr = forms.ChoiceField(required=True, widget=forms.RadioSelect, choices=QEMU_CONSOLE_LISTENER_ADDRESSES)
class Meta:
model = CreateInstance
- fields = '__all__'
- exclude = ['compute']
+ fields = "__all__"
+ exclude = ["compute"]
def clean_name(self):
- name = self.cleaned_data['name']
- have_symbol = re.match('^[a-zA-Z0-9._-]+$', name)
+ name = self.cleaned_data["name"]
+ have_symbol = re.match("^[a-zA-Z0-9._-]+$", name)
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"
+ )
+ )
return name
diff --git a/instances/models.py b/instances/models.py
index 222f886..1488b7e 100644
--- a/instances/models.py
+++ b/instances/models.py
@@ -10,10 +10,10 @@ from vrtManager.instance import wvmInstance
class Flavor(models.Model):
- label = models.CharField(_('label'), max_length=12, unique=True)
- memory = models.IntegerField(_('memory'))
- vcpu = models.IntegerField(_('vcpu'))
- disk = models.IntegerField(_('disk'))
+ label = models.CharField(_("label"), max_length=12, unique=True)
+ memory = models.IntegerField(_("memory"))
+ vcpu = models.IntegerField(_("vcpu"))
+ disk = models.IntegerField(_("disk"))
def __str__(self):
return self.label
@@ -21,21 +21,21 @@ class Flavor(models.Model):
class InstanceManager(models.Manager):
def get_queryset(self):
- return super().get_queryset().select_related('compute')
+ return super().get_queryset().select_related("compute")
class Instance(models.Model):
compute = models.ForeignKey(Compute, on_delete=models.CASCADE)
- name = models.CharField(_('name'), max_length=120, db_index=True)
- uuid = models.CharField(_('uuid'), max_length=36, db_index=True)
- is_template = models.BooleanField(_('is template'), default=False)
- created = models.DateTimeField(_('created'), auto_now_add=True)
- drbd = models.CharField(_('drbd'), max_length=24, default="None")
+ name = models.CharField(_("name"), max_length=120, db_index=True)
+ uuid = models.CharField(_("uuid"), max_length=36, db_index=True)
+ is_template = models.BooleanField(_("is template"), default=False)
+ created = models.DateTimeField(_("created"), auto_now_add=True)
+ drbd = models.CharField(_("drbd"), max_length=24, default="None")
objects = InstanceManager()
def __str__(self):
- return f'{self.compute}/{self.name}'
+ return f"{self.compute}/{self.name}"
@cached_property
def proxy(self):
@@ -173,7 +173,7 @@ class Instance(models.Model):
@cached_property
def snapshots(self):
- return sorted(self.proxy.get_snapshot(), reverse=True, key=lambda k: k['date'])
+ return sorted(self.proxy.get_snapshot(), reverse=True, key=lambda k: k["date"])
@cached_property
def inst_xml(self):
@@ -209,35 +209,59 @@ class Instance(models.Model):
class MigrateInstance(models.Model):
- instance = models.ForeignKey(Instance, related_name='source_host', on_delete=models.DO_NOTHING)
- target_compute = models.ForeignKey(Compute, related_name='target_host', on_delete=models.DO_NOTHING)
+ instance = models.ForeignKey(
+ Instance,
+ related_name="source_host",
+ on_delete=models.DO_NOTHING
+ )
+ target_compute = models.ForeignKey(
+ Compute,
+ related_name="target_host",
+ on_delete=models.DO_NOTHING
+ )
- live = models.BooleanField(_('Live'))
- xml_del = models.BooleanField(_('Undefine XML'), default=True)
- offline = models.BooleanField(_('Offline'))
- autoconverge = models.BooleanField(_('Auto Converge'), default=True)
- compress = models.BooleanField(_('Compress'), default=False)
- postcopy = models.BooleanField(_('Post Copy'), default=False)
- unsafe = models.BooleanField(_('Unsafe'), default=False)
+ live = models.BooleanField(_("Live"))
+ xml_del = models.BooleanField(_("Undefine XML"), default=True)
+ offline = models.BooleanField(_("Offline"))
+ autoconverge = models.BooleanField(_("Auto Converge"), default=True)
+ compress = models.BooleanField(_("Compress"), default=False)
+ postcopy = models.BooleanField(_("Post Copy"), default=False)
+ unsafe = models.BooleanField(_("Unsafe"), default=False)
class Meta:
managed = False
class CreateInstance(models.Model):
- compute = models.ForeignKey(Compute, related_name='host', on_delete=models.DO_NOTHING)
- name = models.CharField(max_length=64, error_messages={'required': _('No Virtual Machine name has been entered')})
+ compute = models.ForeignKey(
+ Compute,
+ related_name="host",
+ on_delete=models.DO_NOTHING
+ )
+ name = models.CharField(
+ max_length=64,
+ error_messages={"required": _("No Virtual Machine name has been entered")},
+ )
firmware = models.CharField(max_length=64)
- vcpu = models.IntegerField(error_messages={'required': _('No VCPU has been entered')})
+ vcpu = models.IntegerField(
+ error_messages={"required": _("No VCPU has been entered")}
+ )
vcpu_mode = models.CharField(max_length=20, blank=True)
disk = models.IntegerField(blank=True)
- memory = models.IntegerField(error_messages={'required': _('No RAM size has been entered')})
- networks = models.CharField(max_length=256, error_messages={'required': _('No Network pool has been choosen')})
+ memory = models.IntegerField(
+ error_messages={"required": _("No RAM size has been entered")}
+ )
+ networks = models.CharField(
+ max_length=256,
+ error_messages={"required": _("No Network pool has been choosen")},
+ )
nwfilter = models.CharField(max_length=256, blank=True)
storage = models.CharField(max_length=256, blank=True)
template = models.CharField(max_length=256, blank=True)
images = models.CharField(max_length=256, blank=True)
- cache_mode = models.CharField(max_length=16, error_messages={'required': _('Please select HDD cache mode')})
+ cache_mode = models.CharField(
+ max_length=16, error_messages={"required": _("Please select HDD cache mode")}
+ )
hdd_size = models.IntegerField(blank=True)
meta_prealloc = models.BooleanField(default=False, blank=True)
virtio = models.BooleanField(default=True)
@@ -246,9 +270,15 @@ class CreateInstance(models.Model):
console_pass = models.CharField(max_length=64, blank=True)
add_cdrom = models.CharField(max_length=16)
add_input = models.CharField(max_length=16)
- graphics = models.CharField(max_length=16, error_messages={'required': _('Please select a graphics type')})
- video = models.CharField(max_length=16, error_messages={'required': _('Please select a video driver')})
- listener_addr = models.CharField(max_length=20, choices=QEMU_CONSOLE_LISTENER_ADDRESSES)
+ graphics = models.CharField(
+ max_length=16, error_messages={"required": _("Please select a graphics type")}
+ )
+ video = models.CharField(
+ max_length=16, error_messages={"required": _("Please select a video driver")}
+ )
+ listener_addr = models.CharField(
+ max_length=20, choices=QEMU_CONSOLE_LISTENER_ADDRESSES
+ )
class Meta:
managed = False
@@ -258,13 +288,14 @@ class PermissionSet(models.Model):
"""
Dummy model for holding set of permissions we need to be automatically added by Django
"""
+
class Meta:
default_permissions = ()
permissions = [
- ('clone_instances', 'Can clone instances'),
- ('passwordless_console', _('Can access console without password')),
- ('view_instances', 'Can view instances'),
- ('snapshot_instances', 'Can snapshot instances'),
+ ("clone_instances", "Can clone instances"),
+ ("passwordless_console", _("Can access console without password")),
+ ("view_instances", "Can view instances"),
+ ("snapshot_instances", "Can snapshot instances"),
]
managed = False
diff --git a/instances/tests.py b/instances/tests.py
index 20e1bfc..ecdc96c 100644
--- a/instances/tests.py
+++ b/instances/tests.py
@@ -25,7 +25,7 @@ class InstancesTestCase(TestCase):
# Add users for testing purposes
User = get_user_model()
cls.admin_user = User.objects.get(pk=1)
- cls.test_user = User.objects.create(username='test-user')
+ cls.test_user = User.objects.create(username="test-user")
UserAttributes.objects.create(
user=cls.test_user,
max_instances=1,
@@ -33,16 +33,16 @@ class InstancesTestCase(TestCase):
max_memory=128,
max_disk_size=1,
)
- permission = Permission.objects.get(codename='clone_instances')
+ permission = Permission.objects.get(codename="clone_instances")
cls.test_user.user_permissions.add(permission)
# Add localhost compute
cls.compute = Compute(
- name='test-compute',
- hostname='localhost',
- login='',
- password='',
- details='local',
+ name="test-compute",
+ hostname="localhost",
+ login="",
+ password="",
+ details="local",
type=4,
)
cls.compute.save()
@@ -56,16 +56,16 @@ class InstancesTestCase(TestCase):
# Add disks for testing
cls.connection.create_volume(
- 'default',
- 'test-volume',
+ "default",
+ "test-volume",
1,
- 'qcow2',
+ "qcow2",
False,
0,
0,
)
# XML for testing vm
- with open('conf/test-vm.xml', 'r') as f:
+ with open("conf/test-vm.xml", "r") as f:
cls.xml = f.read()
# Create testing vm from XML
@@ -81,27 +81,33 @@ class InstancesTestCase(TestCase):
super().tearDownClass()
def setUp(self):
- self.client.login(username='admin', password='admin')
- self.rsa_key = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC6OOdbfv27QVnSC6sKxGaHb6YFc+3gxCkyVR3cTSXE/n5BEGf8aOgBpepULWa1RZfxYHY14PlKULDygdXSdrrR2kNSwoKz/Oo4d+3EE92L7ocl1+djZbptzgWgtw1OseLwbFik+iKlIdqPsH+IUQvX7yV545ZQtAP8Qj1R+uCqkw== test@test'
+ self.client.login(username="admin", password="admin")
+ self.rsa_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC6OOdbfv27QVnSC6sKxGaHb6YFc+3gxCkyVR3cTSXE/n5BEGf8aOgBpepULWa1RZfxYHY14PlKULDygdXSdrrR2kNSwoKz/Oo4d+3EE92L7ocl1+djZbptzgWgtw1OseLwbFik+iKlIdqPsH+IUQvX7yV545ZQtAP8Qj1R+uCqkw== test@test"
def test_index(self):
- response = self.client.get(reverse('instances:index'))
+ response = self.client.get(reverse("instances:index"))
self.assertEqual(response.status_code, 200)
self.client.force_login(self.test_user)
- response = self.client.get(reverse('instances:index'))
+ response = self.client.get(reverse("instances:index"))
self.assertEqual(response.status_code, 200)
def test_create_select_type(self):
- response = self.client.get(reverse('instances:create_instance_select_type', args=[1]))
+ response = self.client.get(
+ reverse("instances:create_instance_select_type", args=[1])
+ )
self.assertEqual(response.status_code, 200)
def test_instance_page(self):
- response = self.client.get(reverse('instances:instance', args=[self.instance.id]))
+ response = self.client.get(
+ reverse("instances:instance", args=[self.instance.id])
+ )
self.assertEqual(response.status_code, 200)
self.client.force_login(self.test_user)
- response = self.client.get(reverse('instances:instance', args=[self.instance.id]))
+ response = self.client.get(
+ reverse("instances:instance", args=[self.instance.id])
+ )
self.assertRaises(Http404)
# def test_create_volume(self):
@@ -118,67 +124,73 @@ class InstancesTestCase(TestCase):
def test_create_destroy_instance(self):
# Create
- response = self.client.get(reverse('instances:create_instance', args=[self.compute.id, 'x86_64', 'q35']))
+ response = self.client.get(
+ reverse(
+ "instances:create_instance", args=[self.compute.id, "x86_64", "q35"]
+ )
+ )
self.assertEqual(response.status_code, 200)
response = self.client.post(
- reverse('instances:create_instance', args=[self.compute.id, 'x86_64', 'q35']),
+ reverse(
+ "instances:create_instance", args=[self.compute.id, "x86_64", "q35"]
+ ),
{
- 'name': 'test',
- 'firmware': 'BIOS',
- 'vcpu': 1,
- 'vcpu_mode': 'host-model',
- 'memory': 128,
- 'device0': 'disk',
- 'bus0': 'virtio',
- 'images': 'test-volume.qcow2',
- 'storage-control': 'default',
- 'image-control': 'test.qcow2',
- 'networks': 'default',
- 'network-control': 'default',
- 'cache_mode': 'directsync',
- 'nwfilter': '',
- 'graphics': 'spice',
- 'video': 'vga',
- 'listener_addr': '0.0.0.0',
- 'console_pass': '',
- 'qemu_ga': False,
- 'virtio': True,
- 'create': True,
+ "name": "test",
+ "firmware": "BIOS",
+ "vcpu": 1,
+ "vcpu_mode": "host-model",
+ "memory": 128,
+ "device0": "disk",
+ "bus0": "virtio",
+ "images": "test-volume.qcow2",
+ "storage-control": "default",
+ "image-control": "test.qcow2",
+ "networks": "default",
+ "network-control": "default",
+ "cache_mode": "directsync",
+ "nwfilter": "",
+ "graphics": "spice",
+ "video": "vga",
+ "listener_addr": "0.0.0.0",
+ "console_pass": "",
+ "qemu_ga": False,
+ "virtio": True,
+ "create": True,
},
)
self.assertEqual(response.status_code, 302)
- instance_qs: Instance = Instance.objects.filter(name='test')
+ instance_qs: Instance = Instance.objects.filter(name="test")
self.assertEqual(len(instance_qs), 1)
instance = instance_qs[0]
# Destroy
- response = self.client.get(reverse('instances:destroy', args=[instance.id]))
+ response = self.client.get(reverse("instances:destroy", args=[instance.id]))
self.assertEqual(response.status_code, 200)
response = self.client.post(
- reverse('instances:destroy', args=[instance.id]),
+ reverse("instances:destroy", args=[instance.id]),
{}, # do not destroy disk image
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
- self.assertRedirects(response, reverse('instances:index'))
+ self.assertRedirects(response, reverse("instances:index"))
def test_create_from_xml(self):
uuid = randomUUID()
- xml = self.xml.replace('test-vm', 'test-vm-xml')
- xml = re.sub('\s?.*?', f'{uuid}', xml)
+ xml = self.xml.replace("test-vm", "test-vm-xml")
+ xml = re.sub("\s?.*?", f"{uuid}", xml)
response = self.client.post(
- reverse('instances:create_instance_select_type', args=[self.compute.id]),
+ reverse("instances:create_instance_select_type", args=[self.compute.id]),
{
- 'create_xml': True,
- 'dom_xml': xml,
+ "create_xml": True,
+ "dom_xml": xml,
},
)
self.assertEqual(response.status_code, 302)
- xml_instance_qs: Instance = Instance.objects.filter(name='test-vm-xml')
+ xml_instance_qs: Instance = Instance.objects.filter(name="test-vm-xml")
self.assertEqual(len(xml_instance_qs), 1)
xml_instance = xml_instance_qs[0]
@@ -187,21 +199,26 @@ class InstancesTestCase(TestCase):
xml_instance.proxy.start()
response = self.client.post(
- reverse('instances:destroy', args=[xml_instance.id]),
+ reverse("instances:destroy", args=[xml_instance.id]),
{}, # do not delete disk image
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
- self.assertRedirects(response, reverse('instances:index'))
+ self.assertRedirects(response, reverse("instances:index"))
def test_resize_cpu(self):
self.assertEqual(self.instance.vcpu, 1)
self.assertEqual(self.instance.cur_vcpu, 1)
- response = self.client.post(reverse('instances:resizevm_cpu', args=[self.instance.id]), {
- 'vcpu': 4,
- 'cur_vcpu': 2,
- })
- self.assertRedirects(response, reverse('instances:instance', args=[self.instance.id]) + '#resize')
+ response = self.client.post(
+ reverse("instances:resizevm_cpu", args=[self.instance.id]),
+ {
+ "vcpu": 4,
+ "cur_vcpu": 2,
+ },
+ )
+ self.assertRedirects(
+ response, reverse("instances:instance", args=[self.instance.id]) + "#resize"
+ )
# reset cached properties
del self.instance.vcpu
@@ -215,15 +232,22 @@ class InstancesTestCase(TestCase):
vcpu = self.instance.vcpu
cur_vcpu = self.instance.cur_vcpu
- UserInstance.objects.create(user=self.test_user, instance=self.instance, is_change=True)
+ UserInstance.objects.create(
+ user=self.test_user, instance=self.instance, is_change=True
+ )
self.client.force_login(self.test_user)
- response = self.client.post(reverse('instances:resizevm_cpu', args=[self.instance.id]), {
- 'vcpu': 4,
- 'cur_vcpu': 2,
- })
- self.assertRedirects(response, reverse('instances:instance', args=[self.instance.id]) + '#resize')
+ response = self.client.post(
+ reverse("instances:resizevm_cpu", args=[self.instance.id]),
+ {
+ "vcpu": 4,
+ "cur_vcpu": 2,
+ },
+ )
+ self.assertRedirects(
+ response, reverse("instances:instance", args=[self.instance.id]) + "#resize"
+ )
del self.instance.vcpu
del self.instance.cur_vcpu
@@ -236,22 +260,26 @@ class InstancesTestCase(TestCase):
self.assertEqual(self.instance.memory, 128)
self.assertEqual(self.instance.cur_memory, 128)
- response = self.client.post(reverse('instances:resize_memory', args=[self.instance.id]), {
- 'memory': 512,
- 'cur_memory': 256
- })
- self.assertRedirects(response, reverse('instances:instance', args=[self.instance.id]) + '#resize')
+ response = self.client.post(
+ reverse("instances:resize_memory", args=[self.instance.id]),
+ {"memory": 512, "cur_memory": 256},
+ )
+ self.assertRedirects(
+ response, reverse("instances:instance", args=[self.instance.id]) + "#resize"
+ )
del self.instance.memory
del self.instance.cur_memory
self.assertEqual(self.instance.memory, 512)
self.assertEqual(self.instance.cur_memory, 256)
- response = self.client.post(reverse('instances:resize_memory', args=[self.instance.id]), {
- 'memory_custom': 500,
- 'cur_memory_custom': 200
- })
- self.assertRedirects(response, reverse('instances:instance', args=[self.instance.id]) + '#resize')
+ response = self.client.post(
+ reverse("instances:resize_memory", args=[self.instance.id]),
+ {"memory_custom": 500, "cur_memory_custom": 200},
+ )
+ self.assertRedirects(
+ response, reverse("instances:instance", args=[self.instance.id]) + "#resize"
+ )
del self.instance.memory
del self.instance.cur_memory
@@ -264,15 +292,19 @@ class InstancesTestCase(TestCase):
memory = self.instance.memory
cur_memory = self.instance.cur_memory
- UserInstance.objects.create(user=self.test_user, instance=self.instance, is_change=True)
+ UserInstance.objects.create(
+ user=self.test_user, instance=self.instance, is_change=True
+ )
self.client.force_login(self.test_user)
- response = self.client.post(reverse('instances:resize_memory', args=[self.instance.id]), {
- 'memory': 512,
- 'cur_memory': 256
- })
- self.assertRedirects(response, reverse('instances:instance', args=[self.instance.id]) + '#resize')
+ response = self.client.post(
+ reverse("instances:resize_memory", args=[self.instance.id]),
+ {"memory": 512, "cur_memory": 256},
+ )
+ self.assertRedirects(
+ response, reverse("instances:instance", args=[self.instance.id]) + "#resize"
+ )
del self.instance.memory
del self.instance.cur_memory
@@ -282,43 +314,55 @@ class InstancesTestCase(TestCase):
self.assertEqual(self.instance.cur_memory, cur_memory)
def test_resize_disk(self):
- self.assertEqual(self.instance.disks[0]['size'], 1024**3)
+ self.assertEqual(self.instance.disks[0]["size"], 1024**3)
- response = self.client.post(reverse('instances:resize_disk', args=[self.instance.id]), {
- 'disk_size_vda': 2,
- })
- self.assertRedirects(response, reverse('instances:instance', args=[self.instance.id]) + '#resize')
+ response = self.client.post(
+ reverse("instances:resize_disk", args=[self.instance.id]),
+ {
+ "disk_size_vda": 2,
+ },
+ )
+ self.assertRedirects(
+ response, reverse("instances:instance", args=[self.instance.id]) + "#resize"
+ )
del self.instance.disks
- self.assertEqual(self.instance.disks[0]['size'], 2 * 1024**3)
+ self.assertEqual(self.instance.disks[0]["size"], 2 * 1024**3)
def test_resize_disk_with_quota(self):
# test for non admin user with quotas
- disk_size = self.instance.disks[0]['size']
- UserInstance.objects.create(user=self.test_user, instance=self.instance, is_change=True)
+ disk_size = self.instance.disks[0]["size"]
+ UserInstance.objects.create(
+ user=self.test_user, instance=self.instance, is_change=True
+ )
self.client.force_login(self.test_user)
- response = self.client.post(reverse('instances:resize_disk', args=[self.instance.id]), {
- 'disk_size_vda': 3,
- })
- self.assertRedirects(response, reverse('instances:instance', args=[self.instance.id]) + '#resize')
+ response = self.client.post(
+ reverse("instances:resize_disk", args=[self.instance.id]),
+ {
+ "disk_size_vda": 3,
+ },
+ )
+ self.assertRedirects(
+ response, reverse("instances:instance", args=[self.instance.id]) + "#resize"
+ )
# no changes as user reached quota
del self.instance.disks
- self.assertEqual(self.instance.disks[0]['size'], disk_size)
+ self.assertEqual(self.instance.disks[0]["size"], disk_size)
def test_add_delete_new_volume(self):
self.assertEqual(len(self.instance.disks), 1)
response = self.client.post(
- reverse('instances:add_new_vol', args=[self.instance.id]),
+ reverse("instances:add_new_vol", args=[self.instance.id]),
{
- 'storage': 'default',
- 'name': 'test-volume-2',
- 'size': 1,
+ "storage": "default",
+ "name": "test-volume-2",
+ "size": 1,
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
@@ -326,13 +370,13 @@ class InstancesTestCase(TestCase):
self.assertEqual(len(self.instance.disks), 2)
response = self.client.post(
- reverse('instances:delete_vol', args=[self.instance.id]),
+ reverse("instances:delete_vol", args=[self.instance.id]),
{
- 'storage': 'default',
- 'dev': 'vdb',
- 'name': 'test-volume-2.qcow2',
+ "storage": "default",
+ "dev": "vdb",
+ "name": "test-volume-2.qcow2",
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
@@ -342,11 +386,11 @@ class InstancesTestCase(TestCase):
def test_detach_attach_volume(self):
# detach volume
response = self.client.post(
- reverse('instances:detach_vol', args=[self.instance.id]),
+ reverse("instances:detach_vol", args=[self.instance.id]),
{
- 'dev': 'vda',
+ "dev": "vda",
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
@@ -355,12 +399,12 @@ class InstancesTestCase(TestCase):
# reattach volume
response = self.client.post(
- reverse('instances:add_existing_vol', args=[self.instance.id]),
+ reverse("instances:add_existing_vol", args=[self.instance.id]),
{
- 'selected_storage': 'default',
- 'vols': 'test-volume.qcow2',
+ "selected_storage": "default",
+ "vols": "test-volume.qcow2",
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
@@ -369,18 +413,18 @@ class InstancesTestCase(TestCase):
def test_edit_volume(self):
response = self.client.post(
- reverse('instances:edit_volume', args=[self.instance.id]),
+ reverse("instances:edit_volume", args=[self.instance.id]),
{
- 'vol_path': '/var/lib/libvirt/images/test-volume.qcow2',
+ "vol_path": "/var/lib/libvirt/images/test-volume.qcow2",
# 'vol_shareable': False,
# 'vol_readonly': False,
- 'vol_bus': 'virtio',
- 'vol_bus_old': 'virtio',
- 'vol_format': 'qcow2',
- 'dev': 'vda',
- 'edit_volume': True
+ "vol_bus": "virtio",
+ "vol_bus_old": "virtio",
+ "vol_format": "qcow2",
+ "dev": "vda",
+ "edit_volume": True,
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
@@ -388,11 +432,11 @@ class InstancesTestCase(TestCase):
self.assertEqual(len(self.instance.media), 1)
response = self.client.post(
- reverse('instances:add_cdrom', args=[self.instance.id]),
+ reverse("instances:add_cdrom", args=[self.instance.id]),
{
- 'bus': 'sata',
+ "bus": "sata",
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
@@ -413,9 +457,9 @@ class InstancesTestCase(TestCase):
# detach CD-ROM drive
response = self.client.post(
- reverse('instances:detach_cdrom', args=[self.instance.id, 'sda']),
+ reverse("instances:detach_cdrom", args=[self.instance.id, "sda"]),
{},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
@@ -426,11 +470,11 @@ class InstancesTestCase(TestCase):
self.assertEqual(len(self.instance.snapshots), 0)
response = self.client.post(
- reverse('instances:snapshot', args=[self.instance.id]),
+ reverse("instances:snapshot", args=[self.instance.id]),
{
- 'name': 'test-snapshot',
+ "name": "test-snapshot",
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
@@ -438,20 +482,20 @@ class InstancesTestCase(TestCase):
self.assertEqual(len(self.instance.snapshots), 1)
response = self.client.post(
- reverse('instances:revert_snapshot', args=[self.instance.id]),
+ reverse("instances:revert_snapshot", args=[self.instance.id]),
{
- 'name': 'test-snapshot',
+ "name": "test-snapshot",
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
response = self.client.post(
- reverse('instances:delete_snapshot', args=[self.instance.id]),
+ reverse("instances:delete_snapshot", args=[self.instance.id]),
{
- 'name': 'test-snapshot',
+ "name": "test-snapshot",
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
@@ -462,9 +506,9 @@ class InstancesTestCase(TestCase):
self.assertEqual(self.instance.autostart, 0)
response = self.client.post(
- reverse('instances:set_autostart', args=[self.instance.id]),
+ reverse("instances:set_autostart", args=[self.instance.id]),
{},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
@@ -472,9 +516,9 @@ class InstancesTestCase(TestCase):
self.assertEqual(self.instance.autostart, 1)
response = self.client.post(
- reverse('instances:unset_autostart', args=[self.instance.id]),
+ reverse("instances:unset_autostart", args=[self.instance.id]),
{},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
@@ -485,9 +529,9 @@ class InstancesTestCase(TestCase):
self.assertEqual(self.instance.bootmenu, True)
response = self.client.post(
- reverse('instances:unset_bootmenu', args=[self.instance.id]),
+ reverse("instances:unset_bootmenu", args=[self.instance.id]),
{},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
@@ -495,9 +539,9 @@ class InstancesTestCase(TestCase):
self.assertEqual(self.instance.bootmenu, False)
response = self.client.post(
- reverse('instances:set_bootmenu', args=[self.instance.id]),
+ reverse("instances:set_bootmenu", args=[self.instance.id]),
{},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
@@ -508,9 +552,9 @@ class InstancesTestCase(TestCase):
self.assertEqual(self.instance.guest_agent, False)
response = self.client.post(
- reverse('instances:set_guest_agent', args=[self.instance.id]),
- {'guest_agent': True},
- HTTP_REFERER=reverse('index'),
+ reverse("instances:set_guest_agent", args=[self.instance.id]),
+ {"guest_agent": True},
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
@@ -518,9 +562,9 @@ class InstancesTestCase(TestCase):
self.assertEqual(self.instance.guest_agent, True)
response = self.client.post(
- reverse('instances:set_guest_agent', args=[self.instance.id]),
- {'guest_agent': False},
- HTTP_REFERER=reverse('index'),
+ reverse("instances:set_guest_agent", args=[self.instance.id]),
+ {"guest_agent": False},
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
@@ -528,24 +572,24 @@ class InstancesTestCase(TestCase):
self.assertEqual(self.instance.guest_agent, False)
def test_video_model(self):
- self.assertEqual(self.instance.video_model, 'vga')
+ self.assertEqual(self.instance.video_model, "vga")
response = self.client.post(
- reverse('instances:set_video_model', args=[self.instance.id]),
- {'video_model': 'virtio'},
- HTTP_REFERER=reverse('index'),
+ reverse("instances:set_video_model", args=[self.instance.id]),
+ {"video_model": "virtio"},
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
del self.instance.video_model
- self.assertEqual(self.instance.video_model, 'virtio')
+ self.assertEqual(self.instance.video_model, "virtio")
def test_owner(self):
self.assertEqual(UserInstance.objects.count(), 0)
response = self.client.post(
- reverse('instances:add_owner', args=[self.instance.id]),
- {'user_id': self.admin_user.id},
- HTTP_REFERER=reverse('index'),
+ reverse("instances:add_owner", args=[self.instance.id]),
+ {"user_id": self.admin_user.id},
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
self.assertEqual(UserInstance.objects.count(), 1)
@@ -555,22 +599,22 @@ class InstancesTestCase(TestCase):
self.assertEqual(user_instance.user_id, self.admin_user.id)
# test when no multiple owners allowed
- setting = AppSettings.objects.get(key='ALLOW_INSTANCE_MULTIPLE_OWNER')
- setting.value = 'False'
+ setting = AppSettings.objects.get(key="ALLOW_INSTANCE_MULTIPLE_OWNER")
+ setting.value = "False"
setting.save()
response = self.client.post(
- reverse('instances:add_owner', args=[self.instance.id]),
- {'user_id': self.test_user.id},
- HTTP_REFERER=reverse('index'),
+ reverse("instances:add_owner", args=[self.instance.id]),
+ {"user_id": self.test_user.id},
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
self.assertEqual(UserInstance.objects.count(), 1)
response = self.client.post(
- reverse('instances:del_owner', args=[self.instance.id]),
- {'userinstance': user_instance.id},
- HTTP_REFERER=reverse('index'),
+ reverse("instances:del_owner", args=[self.instance.id]),
+ {"userinstance": user_instance.id},
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
self.assertEqual(UserInstance.objects.count(), 0)
@@ -578,44 +622,41 @@ class InstancesTestCase(TestCase):
def test_clone(self):
instance_count = Instance.objects.count()
response = self.client.post(
- reverse('instances:clone', args=[self.instance.id]),
+ reverse("instances:clone", args=[self.instance.id]),
{
- 'name': 'test-vm-clone',
- 'clone-net-mac-0': 'de:ad:be:ef:de:ad',
- 'disk-vda': 'test-clone.img',
- 'clone-title': '',
- 'clone-description': '',
- 'clone': '',
+ "name": "test-vm-clone",
+ "clone-net-mac-0": "de:ad:be:ef:de:ad",
+ "disk-vda": "test-clone.img",
+ "clone-title": "",
+ "clone-description": "",
+ "clone": "",
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
self.assertEqual(Instance.objects.count(), instance_count + 1)
- clone_qs = Instance.objects.filter(name='test-vm-clone')
+ clone_qs = Instance.objects.filter(name="test-vm-clone")
self.assertEqual(len(clone_qs), 1)
clone = clone_qs[0]
- self.assertEqual(clone.proxy.get_net_devices()[0]['mac'], 'de:ad:be:ef:de:ad')
+ self.assertEqual(clone.proxy.get_net_devices()[0]["mac"], "de:ad:be:ef:de:ad")
response = self.client.post(
- reverse('instances:snapshot', args=[clone.id]),
+ reverse("instances:snapshot", args=[clone.id]),
{
- 'name': 'test',
+ "name": "test",
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
response = self.client.post(
- reverse('instances:destroy', args=[clone.id]),
- {
- 'delete_disk': True,
- 'delete_nvram': True
- },
- HTTP_REFERER=reverse('index'),
+ reverse("instances:destroy", args=[clone.id]),
+ {"delete_disk": True, "delete_nvram": True},
+ HTTP_REFERER=reverse("index"),
)
- self.assertRedirects(response, reverse('instances:index'))
+ self.assertRedirects(response, reverse("instances:index"))
self.assertEqual(Instance.objects.count(), instance_count)
def test_clone_with_quota(self):
@@ -627,16 +668,16 @@ class InstancesTestCase(TestCase):
self.client.force_login(self.test_user)
response = self.client.post(
- reverse('instances:clone', args=[self.instance.id]),
+ reverse("instances:clone", args=[self.instance.id]),
{
- 'name': 'test-vm-clone',
- 'clone-net-mac-0': 'de:ad:be:ef:de:ad',
- 'disk-vda': 'test-clone.img',
- 'clone-title': '',
- 'clone-description': '',
- 'clone': '',
+ "name": "test-vm-clone",
+ "clone-net-mac-0": "de:ad:be:ef:de:ad",
+ "disk-vda": "test-clone.img",
+ "clone-title": "",
+ "clone-description": "",
+ "clone": "",
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
# no new instances created as user reached quota
@@ -647,99 +688,104 @@ class InstancesTestCase(TestCase):
# duplicate name
response = self.client.post(
- reverse('instances:clone', args=[self.instance.id]),
+ reverse("instances:clone", args=[self.instance.id]),
{
- 'name': 'test-vm',
- 'clone-net-mac-0': 'de:ad:be:ef:de:ad',
- 'disk-vda': 'test.img',
- 'clone-title': '',
- 'clone-description': '',
- 'clone': '',
+ "name": "test-vm",
+ "clone-net-mac-0": "de:ad:be:ef:de:ad",
+ "disk-vda": "test.img",
+ "clone-title": "",
+ "clone-description": "",
+ "clone": "",
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
self.assertEqual(Instance.objects.count(), instance_count)
# wrong name
response = self.client.post(
- reverse('instances:clone', args=[self.instance.id]),
+ reverse("instances:clone", args=[self.instance.id]),
{
- 'name': '!@#$',
- 'clone-net-mac-0': 'de:ad:be:ef:de:ad',
- 'disk-vda': '!@#$.img',
- 'clone-title': '',
- 'clone-description': '',
- 'clone': '',
+ "name": "!@#$",
+ "clone-net-mac-0": "de:ad:be:ef:de:ad",
+ "disk-vda": "!@#$.img",
+ "clone-title": "",
+ "clone-description": "",
+ "clone": "",
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
self.assertEqual(Instance.objects.count(), instance_count)
# wrong mac
response = self.client.post(
- reverse('instances:clone', args=[self.instance.id]),
+ reverse("instances:clone", args=[self.instance.id]),
{
- 'name': 'test-vm-clone',
- 'clone-net-mac-0': 'gh:ad:be:ef:de:ad',
- 'disk-vda': 'test-clone.img',
- 'clone-title': '',
- 'clone-description': '',
- 'clone': '',
+ "name": "test-vm-clone",
+ "clone-net-mac-0": "gh:ad:be:ef:de:ad",
+ "disk-vda": "test-clone.img",
+ "clone-title": "",
+ "clone-description": "",
+ "clone": "",
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
self.assertEqual(Instance.objects.count(), instance_count)
def test_console(self):
response = self.client.post(
- reverse('instances:update_console', args=[self.instance.id]),
- {
- 'type': 'spice',
- 'listen_on': '0.0.0.0',
- 'password': '',
- 'keymap': 'auto'
- },
- HTTP_REFERER=reverse('index'),
+ reverse("instances:update_console", args=[self.instance.id]),
+ {"type": "spice", "listen_on": "0.0.0.0", "password": "", "keymap": "auto"},
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
def test_status(self):
- response = self.client.get(reverse('instances:status', args=[self.instance.id]))
+ response = self.client.get(reverse("instances:status", args=[self.instance.id]))
self.assertEqual(response.status_code, 200)
def test_stats(self):
- response = self.client.get(reverse('instances:stats', args=[self.instance.id]))
+ response = self.client.get(reverse("instances:stats", args=[self.instance.id]))
self.assertEqual(response.status_code, 200)
def test_guess_mac_address(self):
- response = self.client.get(reverse('instances:guess_mac_address', args=[self.instance.name]))
+ response = self.client.get(
+ reverse("instances:guess_mac_address", args=[self.instance.name])
+ )
self.assertEqual(response.status_code, 200)
def test_random_mac_address(self):
- response = self.client.get(reverse('instances:random_mac_address'))
+ response = self.client.get(reverse("instances:random_mac_address"))
self.assertEqual(response.status_code, 200)
def test_guess_clone_name(self):
- response = self.client.get(reverse('instances:guess_clone_name'))
+ response = self.client.get(reverse("instances:guess_clone_name"))
self.assertEqual(response.status_code, 200)
def test_sshkeys(self):
- UserSSHKey.objects.create(keyname='keyname', keypublic=self.rsa_key, user=self.test_user)
+ UserSSHKey.objects.create(
+ keyname="keyname", keypublic=self.rsa_key, user=self.test_user
+ )
UserInstance.objects.create(user=self.test_user, instance=self.instance)
- response = self.client.get(reverse('instances:sshkeys', args=[self.instance.id]))
+ response = self.client.get(
+ reverse("instances:sshkeys", args=[self.instance.id])
+ )
self.assertEqual(response.status_code, 200)
- response = self.client.get(reverse('instances:sshkeys', args=[self.instance.id]) + '?plain=true')
+ response = self.client.get(
+ reverse("instances:sshkeys", args=[self.instance.id]) + "?plain=true"
+ )
self.assertEqual(response.status_code, 200)
def test_check_instance(self):
- response = self.client.get(reverse('instances:check_instance', args=['test-vm']))
+ response = self.client.get(
+ reverse("instances:check_instance", args=["test-vm"])
+ )
self.assertEqual(response.status_code, 200)
- self.assertJSONEqual(response.content, {'vname': 'test-vm', 'exists': True})
+ self.assertJSONEqual(response.content, {"vname": "test-vm", "exists": True})
def test_start_template(self):
# starting templates must fail
@@ -748,7 +794,10 @@ class InstancesTestCase(TestCase):
self.instance.is_template = True
self.instance.save()
- response = self.client.get(reverse('instances:poweron', args=[self.instance.id]), HTTP_REFERER=reverse('index'))
+ response = self.client.get(
+ reverse("instances:poweron", args=[self.instance.id]),
+ HTTP_REFERER=reverse("index"),
+ )
self.assertEqual(response.status_code, 302)
del self.instance.status
@@ -761,7 +810,10 @@ class InstancesTestCase(TestCase):
# poweron
self.assertEqual(self.instance.status, 5)
- response = self.client.get(reverse('instances:poweron', args=[self.instance.id]), HTTP_REFERER=reverse('index'))
+ response = self.client.get(
+ reverse("instances:poweron", args=[self.instance.id]),
+ HTTP_REFERER=reverse("index"),
+ )
self.assertEqual(response.status_code, 302)
del self.instance.status
@@ -769,21 +821,30 @@ class InstancesTestCase(TestCase):
self.assertEqual(self.instance.status, 1)
# suspend
- response = self.client.get(reverse('instances:suspend', args=[self.instance.id]), HTTP_REFERER=reverse('index'))
+ response = self.client.get(
+ reverse("instances:suspend", args=[self.instance.id]),
+ HTTP_REFERER=reverse("index"),
+ )
self.assertEqual(response.status_code, 302)
del self.instance.status
self.assertEqual(self.instance.status, 3)
# resume
- response = self.client.get(reverse('instances:resume', args=[self.instance.id]), HTTP_REFERER=reverse('index'))
+ response = self.client.get(
+ reverse("instances:resume", args=[self.instance.id]),
+ HTTP_REFERER=reverse("index"),
+ )
self.assertEqual(response.status_code, 302)
del self.instance.status
self.assertEqual(self.instance.status, 1)
# poweroff
- response = self.client.get(reverse('instances:poweroff', args=[self.instance.id]), HTTP_REFERER=reverse('index'))
+ response = self.client.get(
+ reverse("instances:poweroff", args=[self.instance.id]),
+ HTTP_REFERER=reverse("index"),
+ )
self.assertEqual(response.status_code, 302)
# as no OS is installed ACPI won't work
@@ -791,107 +852,115 @@ class InstancesTestCase(TestCase):
self.assertEqual(self.instance.status, 1)
# powercycle
- response = self.client.get(reverse('instances:powercycle', args=[self.instance.id]), HTTP_REFERER=reverse('index'))
+ response = self.client.get(
+ reverse("instances:powercycle", args=[self.instance.id]),
+ HTTP_REFERER=reverse("index"),
+ )
self.assertEqual(response.status_code, 302)
del self.instance.status
self.assertEqual(self.instance.status, 1)
# force_off
- response = self.client.get(reverse('instances:force_off', args=[self.instance.id]), HTTP_REFERER=reverse('index'))
+ response = self.client.get(
+ reverse("instances:force_off", args=[self.instance.id]),
+ HTTP_REFERER=reverse("index"),
+ )
self.assertEqual(response.status_code, 302)
del self.instance.status
self.assertEqual(self.instance.status, 5)
def test_vv_file(self):
- response = self.client.get(reverse('instances:getvvfile', args=[self.instance.id]))
+ response = self.client.get(
+ reverse("instances:getvvfile", args=[self.instance.id])
+ )
self.assertEqual(response.status_code, 200)
def test_vcpu_hotplug(self):
response = self.client.post(
- reverse('instances:set_vcpu_hotplug', args=[self.instance.id]),
- {'vcpu_hotplug': 'True'},
- HTTP_REFERER=reverse('index'),
+ reverse("instances:set_vcpu_hotplug", args=[self.instance.id]),
+ {"vcpu_hotplug": "True"},
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
def test_change_network(self):
- self.assertEqual(self.instance.networks[0]['mac'], '52:54:00:a2:3c:e7')
+ self.assertEqual(self.instance.networks[0]["mac"], "52:54:00:a2:3c:e7")
response = self.client.post(
- reverse('instances:change_network', args=[self.instance.id]),
+ reverse("instances:change_network", args=[self.instance.id]),
{
- 'net-mac-0': '52:54:00:a2:3c:e8',
- 'net-source-0': 'net:default',
- 'net-nwfilter-0': '',
- 'net-model-0': 'virtio',
+ "net-mac-0": "52:54:00:a2:3c:e8",
+ "net-source-0": "net:default",
+ "net-nwfilter-0": "",
+ "net-model-0": "virtio",
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
del self.instance.networks
- self.assertEqual(self.instance.networks[0]['mac'], '52:54:00:a2:3c:e8')
+ self.assertEqual(self.instance.networks[0]["mac"], "52:54:00:a2:3c:e8")
def test_add_delete_network(self):
self.assertEqual(len(self.instance.networks), 1)
- net_mac = self.instance.networks[0]['mac']
+ net_mac = self.instance.networks[0]["mac"]
response = self.client.post(
- reverse('instances:add_network', args=[self.instance.id]),
+ reverse("instances:add_network", args=[self.instance.id]),
{
- 'add-net-mac': '52:54:00:a2:3c:e9',
- 'add-net-network': 'net:default',
- 'add_net-nwfilter': '',
+ "add-net-mac": "52:54:00:a2:3c:e9",
+ "add-net-network": "net:default",
+ "add_net-nwfilter": "",
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
del self.instance.networks
self.assertEqual(len(self.instance.networks), 2)
- self.assertEqual(self.instance.networks[1]['mac'], '52:54:00:a2:3c:e9')
+ self.assertEqual(self.instance.networks[1]["mac"], "52:54:00:a2:3c:e9")
response = self.client.post(
- reverse('instances:delete_network', args=[self.instance.id]),
+ reverse("instances:delete_network", args=[self.instance.id]),
{
- 'delete_network': '52:54:00:a2:3c:e9',
+ "delete_network": "52:54:00:a2:3c:e9",
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
del self.instance.networks
self.assertEqual(len(self.instance.networks), 1)
- self.assertEqual(self.instance.networks[0]['mac'], net_mac)
+ self.assertEqual(self.instance.networks[0]["mac"], net_mac)
def test_set_link_state(self):
- self.assertEqual(self.instance.networks[0]['state'], 'up')
+ self.assertEqual(self.instance.networks[0]["state"], "up")
response = self.client.post(
- reverse('instances:set_link_state', args=[self.instance.id]),
+ reverse("instances:set_link_state", args=[self.instance.id]),
{
- 'mac': self.instance.networks[0]['mac'],
- 'set_link_state': 'up',
+ "mac": self.instance.networks[0]["mac"],
+ "set_link_state": "up",
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
del self.instance.networks
- self.assertEqual(self.instance.networks[0]['state'], 'down')
+ self.assertEqual(self.instance.networks[0]["state"], "down")
def test_set_unset_qos(self):
self.assertEqual(len(self.instance.qos.keys()), 0)
- net_mac = self.instance.networks[0]['mac']
+ net_mac = self.instance.networks[0]["mac"]
response = self.client.post(
- reverse('instances:set_qos', args=[self.instance.id]),
+ reverse("instances:set_qos", args=[self.instance.id]),
{
- 'net-mac-0': net_mac,
- 'qos_direction': 'inbound',
- 'qos_average': 1,
- 'qos_peak': 1,
- 'qos_burst': 1,
+ "net-mac-0": net_mac,
+ "qos_direction": "inbound",
+ "qos_average": 1,
+ "qos_peak": 1,
+ "qos_burst": 1,
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
@@ -899,12 +968,12 @@ class InstancesTestCase(TestCase):
self.assertEqual(len(self.instance.qos.keys()), 1)
response = self.client.post(
- reverse('instances:unset_qos', args=[self.instance.id]),
+ reverse("instances:unset_qos", args=[self.instance.id]),
{
- 'net-mac': net_mac,
- 'qos_direction': 'inbound',
+ "net-mac": net_mac,
+ "qos_direction": "inbound",
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
del self.instance.qos
@@ -927,65 +996,65 @@ class InstancesTestCase(TestCase):
# self.instance.proxy.force_shutdown()
def test_change_options(self):
- self.assertEqual(self.instance.title, '')
- self.assertEqual(self.instance.description, '')
+ self.assertEqual(self.instance.title, "")
+ self.assertEqual(self.instance.description, "")
response = self.client.post(
- reverse('instances:change_options', args=[self.instance.id]),
+ reverse("instances:change_options", args=[self.instance.id]),
{
- 'title': 'test-vm-title',
- 'description': 'test-vm description',
+ "title": "test-vm-title",
+ "description": "test-vm description",
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
del self.instance.title
del self.instance.description
- self.assertEqual(self.instance.title, 'test-vm-title')
- self.assertEqual(self.instance.description, 'test-vm description')
+ self.assertEqual(self.instance.title, "test-vm-title")
+ self.assertEqual(self.instance.description, "test-vm description")
def test_flavors(self):
- response = self.client.get(reverse('instances:flavor_create'))
+ response = self.client.get(reverse("instances:flavor_create"))
self.assertEqual(response.status_code, 200)
response = self.client.post(
- reverse('instances:flavor_create'),
+ reverse("instances:flavor_create"),
{
- 'label': 'test_flavor',
- 'memory': 256,
- 'vcpu': 1,
- 'disk': 10,
+ "label": "test_flavor",
+ "memory": 256,
+ "vcpu": 1,
+ "disk": 10,
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
id = Flavor.objects.last().id
- response = self.client.get(reverse('instances:flavor_update', args=[id]))
+ response = self.client.get(reverse("instances:flavor_update", args=[id]))
self.assertEqual(response.status_code, 200)
response = self.client.post(
- reverse('instances:flavor_update', args=[id]),
+ reverse("instances:flavor_update", args=[id]),
{
- 'label': 'test_flavor_',
- 'memory': 256,
- 'vcpu': 1,
- 'disk': 10,
+ "label": "test_flavor_",
+ "memory": 256,
+ "vcpu": 1,
+ "disk": 10,
},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
- response = self.client.get(reverse('instances:flavor_delete', args=[id]))
+ response = self.client.get(reverse("instances:flavor_delete", args=[id]))
self.assertEqual(response.status_code, 200)
response = self.client.post(
- reverse('instances:flavor_delete', args=[id]),
+ reverse("instances:flavor_delete", args=[id]),
{},
- HTTP_REFERER=reverse('index'),
+ HTTP_REFERER=reverse("index"),
)
self.assertEqual(response.status_code, 302)
diff --git a/instances/urls.py b/instances/urls.py
index de12a83..c7a74f9 100644
--- a/instances/urls.py
+++ b/instances/urls.py
@@ -2,69 +2,83 @@ from django.urls import path
from . import views
-app_name = 'instances'
+app_name = "instances"
urlpatterns = [
- path('', views.index, name='index'),
- path('flavor/create/', views.flavor_create, name='flavor_create'),
- path('flavor//update/', views.flavor_update, name='flavor_update'),
- path('flavor//delete/', views.flavor_delete, name='flavor_delete'),
- path('/', views.instance, name='instance'),
- path('/poweron/', views.poweron, name='poweron'),
- path('/powercycle/', views.powercycle, name='powercycle'),
- path('/poweroff/', views.poweroff, name='poweroff'),
- path('/suspend/', views.suspend, name='suspend'),
- path('/resume/', views.resume, name='resume'),
- path('/force_off/', views.force_off, name='force_off'),
- path('/destroy/', views.destroy, name='destroy'),
- path('/migrate/', views.migrate, name='migrate'),
- path('/status/', views.status, name='status'),
- path('/stats/', views.stats, name='stats'),
- path('/osinfo/', views.osinfo, name='osinfo'),
- path('/rootpasswd/', views.set_root_pass, name='rootpasswd'),
- path('/add_public_key/', views.add_public_key, name='add_public_key'),
- path('/resizevm_cpu/', views.resizevm_cpu, name='resizevm_cpu'),
- path('/resize_memory/', views.resize_memory, name='resize_memory'),
- path('/resize_disk/', views.resize_disk, name='resize_disk'),
- path('/add_new_vol/', views.add_new_vol, name='add_new_vol'),
- path('/delete_vol/', views.delete_vol, name='delete_vol'),
- path('/add_owner/', views.add_owner, name='add_owner'),
- path('/add_existing_vol/', views.add_existing_vol, name='add_existing_vol'),
- path('/edit_volume/', views.edit_volume, name='edit_volume'),
- path('/detach_vol/', views.detach_vol, name='detach_vol'),
- path('/add_cdrom/', views.add_cdrom, name='add_cdrom'),
- path('/detach_cdrom//', views.detach_cdrom, name='detach_cdrom'),
- path('/unmount_iso/', views.unmount_iso, name='unmount_iso'),
- path('/mount_iso/', views.mount_iso, name='mount_iso'),
- path('/snapshot/', views.snapshot, name='snapshot'),
- path('/delete_snapshot/', views.delete_snapshot, name='delete_snapshot'),
- path('/revert_snapshot/', views.revert_snapshot, name='revert_snapshot'),
- path('/set_vcpu/', views.set_vcpu, name='set_vcpu'),
- path('/set_vcpu_hotplug/', views.set_vcpu_hotplug, name='set_vcpu_hotplug'),
- path('/set_autostart/', views.set_autostart, name='set_autostart'),
- path('/unset_autostart/', views.unset_autostart, name='unset_autostart'),
- path('/set_bootmenu/', views.set_bootmenu, name='set_bootmenu'),
- path('/unset_bootmenu/', views.unset_bootmenu, name='unset_bootmenu'),
- path('/set_bootorder/', views.set_bootorder, name='set_bootorder'),
- path('/change_xml/', views.change_xml, name='change_xml'),
- path('/set_guest_agent/', views.set_guest_agent, name='set_guest_agent'),
- path('/set_video_model/', views.set_video_model, name='set_video_model'),
- path('/change_network/', views.change_network, name='change_network'),
- path('/add_network/', views.add_network, name='add_network'),
- path('/delete_network/', views.delete_network, name='delete_network'),
- path('/set_link_state/', views.set_link_state, name='set_link_state'),
- path('/set_qos/', views.set_qos, name='set_qos'),
- path('/unset_qos/', views.unset_qos, name='unset_qos'),
- path('/del_owner/', views.del_owner, name='del_owner'), # no links to this one???
- path('/clone/', views.clone, name='clone'),
- path('/update_console/', views.update_console, name='update_console'),
- path('/change_options/', views.change_options, name='change_options'),
- path('/getvvfile/', views.getvvfile, name='getvvfile'), # no links to this one???
- path('create//', views.create_instance_select_type, name='create_instance_select_type'),
- path('create////', views.create_instance, name='create_instance'),
- path('guess_mac_address//', views.guess_mac_address, name='guess_mac_address'),
- 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('check_instance//', views.check_instance, name='check_instance'),
- path('/sshkeys/', views.sshkeys, name='sshkeys'),
+ path("", views.index, name="index"),
+ path("flavor/create/", views.flavor_create, name="flavor_create"),
+ path("flavor//update/", views.flavor_update, name="flavor_update"),
+ path("flavor//delete/", views.flavor_delete, name="flavor_delete"),
+ path("/", views.instance, name="instance"),
+ path("/poweron/", views.poweron, name="poweron"),
+ path("/powercycle/", views.powercycle, name="powercycle"),
+ path("/poweroff/", views.poweroff, name="poweroff"),
+ path("/suspend/", views.suspend, name="suspend"),
+ path("/resume/", views.resume, name="resume"),
+ path("/force_off/", views.force_off, name="force_off"),
+ path("/destroy/", views.destroy, name="destroy"),
+ path("/migrate/", views.migrate, name="migrate"),
+ path("/status/", views.status, name="status"),
+ path("/stats/", views.stats, name="stats"),
+ path("/osinfo/", views.osinfo, name="osinfo"),
+ path("/rootpasswd/", views.set_root_pass, name="rootpasswd"),
+ path("/add_public_key/", views.add_public_key, name="add_public_key"),
+ path("/resizevm_cpu/", views.resizevm_cpu, name="resizevm_cpu"),
+ path("/resize_memory/", views.resize_memory, name="resize_memory"),
+ path("/resize_disk/", views.resize_disk, name="resize_disk"),
+ path("/add_new_vol/", views.add_new_vol, name="add_new_vol"),
+ path("/delete_vol/", views.delete_vol, name="delete_vol"),
+ path("/add_owner/", views.add_owner, name="add_owner"),
+ path("/add_existing_vol/", views.add_existing_vol, name="add_existing_vol"),
+ path("/edit_volume/", views.edit_volume, name="edit_volume"),
+ path("/detach_vol/", views.detach_vol, name="detach_vol"),
+ path("/add_cdrom/", views.add_cdrom, name="add_cdrom"),
+ path("/detach_cdrom//", views.detach_cdrom, name="detach_cdrom"),
+ path("/unmount_iso/", views.unmount_iso, name="unmount_iso"),
+ path("/mount_iso/", views.mount_iso, name="mount_iso"),
+ path("/snapshot/", views.snapshot, name="snapshot"),
+ path("/delete_snapshot/", views.delete_snapshot, name="delete_snapshot"),
+ path("/revert_snapshot/", views.revert_snapshot, name="revert_snapshot"),
+ path("/set_vcpu/", views.set_vcpu, name="set_vcpu"),
+ path("/set_vcpu_hotplug/", views.set_vcpu_hotplug, name="set_vcpu_hotplug"),
+ path("/set_autostart/", views.set_autostart, name="set_autostart"),
+ path("/unset_autostart/", views.unset_autostart, name="unset_autostart"),
+ path("/set_bootmenu/", views.set_bootmenu, name="set_bootmenu"),
+ path("/unset_bootmenu/", views.unset_bootmenu, name="unset_bootmenu"),
+ path("/set_bootorder/", views.set_bootorder, name="set_bootorder"),
+ path("/change_xml/", views.change_xml, name="change_xml"),
+ path("/set_guest_agent/", views.set_guest_agent, name="set_guest_agent"),
+ path("/set_video_model/", views.set_video_model, name="set_video_model"),
+ path("/change_network/", views.change_network, name="change_network"),
+ path("/add_network/", views.add_network, name="add_network"),
+ path("/delete_network/", views.delete_network, name="delete_network"),
+ path("/set_link_state/", views.set_link_state, name="set_link_state"),
+ path("/set_qos/", views.set_qos, name="set_qos"),
+ path("/unset_qos/", views.unset_qos, name="unset_qos"),
+ path(
+ "/del_owner/", views.del_owner, name="del_owner"
+ ), # no links to this one???
+ path("/clone/", views.clone, name="clone"),
+ path("/update_console/", views.update_console, name="update_console"),
+ path("/change_options/", views.change_options, name="change_options"),
+ path(
+ "/getvvfile/", views.getvvfile, name="getvvfile"
+ ), # no links to this one???
+ path(
+ "create//",
+ views.create_instance_select_type,
+ name="create_instance_select_type",
+ ),
+ path(
+ "create////",
+ views.create_instance,
+ name="create_instance",
+ ),
+ path(
+ "guess_mac_address//", views.guess_mac_address, name="guess_mac_address"
+ ),
+ 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("check_instance//", views.check_instance, name="check_instance"),
+ path("/sshkeys/", views.sshkeys, name="sshkeys"),
]
diff --git a/instances/utils.py b/instances/utils.py
index a7c3f44..53752b6 100644
--- a/instances/utils.py
+++ b/instances/utils.py
@@ -38,8 +38,8 @@ def check_user_quota(user, instance, cpu, memory, disk_size):
instance += user_instances.count()
for usr_inst in user_instances:
if connection_manager.host_is_up(
- usr_inst.instance.compute.type,
- usr_inst.instance.compute.hostname,
+ usr_inst.instance.compute.type,
+ usr_inst.instance.compute.hostname,
):
conn = wvmInstance(
usr_inst.instance.compute.hostname,
@@ -51,8 +51,8 @@ def check_user_quota(user, instance, cpu, memory, disk_size):
cpu += int(conn.get_vcpu())
memory += int(conn.get_memory())
for disk in conn.get_disk_devices():
- if disk['size']:
- disk_size += int(disk['size']) >> 30
+ if disk["size"]:
+ disk_size += int(disk["size"]) >> 30
if ua.max_instances > 0 and instance > ua.max_instances:
msg = "instance"
@@ -86,17 +86,17 @@ def get_new_disk_dev(media, disks, bus):
dev_base = "sd"
if disks:
- existing_disk_devs = [disk['dev'] for disk in disks]
+ existing_disk_devs = [disk["dev"] for disk in disks]
# cd-rom bus could be virtio/sata, because of that we should check it also
if media:
- existing_media_devs = [m['dev'] for m in media]
+ existing_media_devs = [m["dev"] for m in media]
for al in string.ascii_lowercase:
dev = dev_base + al
if dev not in existing_disk_devs and dev not in existing_media_devs:
return dev
- raise Exception(_('None available device name'))
+ raise Exception(_("None available device name"))
def get_network_tuple(network_source_str):
@@ -104,7 +104,7 @@ def get_network_tuple(network_source_str):
if len(network_source_pack) > 1:
return network_source_pack[1], network_source_pack[0]
else:
- return network_source_pack[0], 'net'
+ return network_source_pack[0], "net"
def migrate_instance(
@@ -174,44 +174,44 @@ def refr(compute):
Instance.objects.filter(compute=compute).exclude(name__in=domain_names).delete()
Instance.objects.filter(compute=compute).exclude(uuid__in=domain_uuids).delete()
# Create instances that're not in DB
- names = Instance.objects.filter(compute=compute).values_list('name', flat=True)
+ names = Instance.objects.filter(compute=compute).values_list("name", flat=True)
for domain in domains:
if domain.name() not in names:
Instance(compute=compute, name=domain.name(), uuid=domain.UUIDString()).save()
def get_dhcp_mac_address(vname):
- dhcp_file = str(settings.BASE_DIR) + '/dhcpd.conf'
- mac = ''
+ dhcp_file = str(settings.BASE_DIR) + "/dhcpd.conf"
+ mac = ""
if os.path.isfile(dhcp_file):
- with open(dhcp_file, 'r') as f:
+ with open(dhcp_file, "r") as f:
name_found = False
for line in f:
if "host %s." % vname in line:
name_found = True
if name_found and "hardware ethernet" in line:
- mac = line.split(' ')[-1].strip().strip(';')
+ mac = line.split(" ")[-1].strip().strip(";")
break
return mac
def get_random_mac_address():
- mac = '52:54:00:%02x:%02x:%02x' % (
- random.randint(0x00, 0xff),
- random.randint(0x00, 0xff),
- random.randint(0x00, 0xff),
+ mac = "52:54:00:%02x:%02x:%02x" % (
+ random.randint(0x00, 0xFF),
+ random.randint(0x00, 0xFF),
+ random.randint(0x00, 0xFF),
)
return mac
-def get_clone_disk_name(disk, prefix, clone_name=''):
- if not disk['image']:
+def get_clone_disk_name(disk, prefix, clone_name=""):
+ if not disk["image"]:
return None
- if disk['image'].startswith(prefix) and clone_name:
- suffix = disk['image'][len(prefix):]
+ if disk["image"].startswith(prefix) and clone_name:
+ suffix = disk["image"][len(prefix) :]
image = f"{clone_name}{suffix}"
- elif "." in disk['image'] and len(disk['image'].rsplit(".", 1)[1]) <= 7:
- name, suffix = disk['image'].rsplit(".", 1)
+ elif "." in disk["image"] and len(disk["image"].rsplit(".", 1)[1]) <= 7:
+ name, suffix = disk["image"].rsplit(".", 1)
image = f"{name}-clone.{suffix}"
else:
image = f"{disk['image']}-clone"
diff --git a/instances/views.py b/instances/views.py
index d19cba3..ef979b0 100644
--- a/instances/views.py
+++ b/instances/views.py
@@ -21,7 +21,11 @@ from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from instances.models import Instance
-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 vrtManager import util
from vrtManager.create import wvmCreate
@@ -50,9 +54,13 @@ def index(request):
if request.user.is_superuser or request.user.has_perm("instances.view_instances"):
instances = Instance.objects.all().prefetch_related("userinstance_set")
else:
- instances = Instance.objects.filter(userinstance__user=request.user).prefetch_related("userinstance_set")
+ instances = Instance.objects.filter(
+ userinstance__user=request.user
+ ).prefetch_related("userinstance_set")
- return render(request, "allinstances.html", {"computes": computes, "instances": instances})
+ return render(
+ request, "allinstances.html", {"computes": computes, "instances": instances}
+ )
def instance(request, pk):
@@ -63,7 +71,9 @@ def instance(request, pk):
users = User.objects.all().order_by("username")
publickeys = UserSSHKey.objects.filter(user_id=request.user.id)
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(
initial={
"type": instance.console_type,
@@ -74,10 +84,14 @@ def instance(request, pk):
)
console_listener_addresses = settings.QEMU_CONSOLE_LISTENER_ADDRESSES
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
+ )
try:
userinstance = UserInstance.objects.get(
- instance__compute_id=compute.id, instance__name=instance.name, user__id=request.user.id
+ instance__compute_id=compute.id,
+ instance__name=instance.name,
+ user__id=request.user.id,
)
except UserInstance.DoesNotExist:
userinstance = None
@@ -116,7 +130,9 @@ def instance(request, pk):
# userinstances = UserInstance.objects.filter(instance=instance).order_by('user__username')
userinstances = instance.userinstance_set.order_by("user__username")
- 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
+ )
# Host resources
vcpu_host = len(instance.vcpu_range)
@@ -128,7 +144,7 @@ def instance(request, pk):
storages_host = sorted(instance.proxy.get_storages(True))
net_models_host = instance.proxy.get_network_models()
- if app_settings.VM_DRBD_STATUS == 'True':
+ if app_settings.VM_DRBD_STATUS == "True":
instance.drbd = drbd_status(request, pk)
instance.save()
@@ -139,17 +155,25 @@ def status(request, pk):
instance = get_instance(request.user, pk)
return JsonResponse({"status": instance.proxy.get_status()})
+
def drbd_status(request, pk):
instance = get_instance(request.user, pk)
result = "None DRBD"
if instance.compute.type == 2:
conn = instance.compute.login + "@" + instance.compute.hostname
- remoteDrbdStatus = subprocess.run(["ssh", conn, "sudo", "/usr/sbin/drbdadm", "status", "&&", "exit"], stdout=subprocess.PIPE, text=True)
+ remoteDrbdStatus = subprocess.run(
+ ["ssh", conn, "sudo", "/usr/sbin/drbdadm", "status", "&&", "exit"],
+ stdout=subprocess.PIPE,
+ text=True,
+ )
if remoteDrbdStatus.stdout:
try:
- instanceFindDrbd = re.compile(instance.name + '[_]*[A-Z]* role:(.+?)\n disk:(.+?)\n', re.IGNORECASE)
+ instanceFindDrbd = re.compile(
+ instance.name + "[_]*[A-Z]* role:(.+?)\n disk:(.+?)\n",
+ re.IGNORECASE,
+ )
instanceDrbd = instanceFindDrbd.findall(remoteDrbdStatus.stdout)
primaryCount = 0
@@ -179,6 +203,7 @@ def drbd_status(request, pk):
return result
+
def stats(request, pk):
instance = get_instance(request.user, pk)
json_blk = []
@@ -192,10 +217,20 @@ def stats(request, pk):
current_time = time.strftime("%H:%M:%S")
for blk in blk_usage:
- json_blk.append({"dev": blk["dev"], "data": [int(blk["rd"]) / 1048576, int(blk["wr"]) / 1048576]})
+ json_blk.append(
+ {
+ "dev": blk["dev"],
+ "data": [int(blk["rd"]) / 1048576, int(blk["wr"]) / 1048576],
+ }
+ )
for net in net_usage:
- json_net.append({"dev": net["dev"], "data": [int(net["rx"]) / 1048576, int(net["tx"]) / 1048576]})
+ json_net.append(
+ {
+ "dev": net["dev"],
+ "data": [int(net["rx"]) / 1048576, int(net["tx"]) / 1048576],
+ }
+ )
return JsonResponse(
{
@@ -207,12 +242,14 @@ def stats(request, pk):
}
)
+
def osinfo(request, pk):
instance = get_instance(request.user, pk)
results = instance.proxy.osinfo()
-
+
return JsonResponse(results)
+
def guess_mac_address(request, vname):
data = {"vname": vname}
mac = utils.get_dhcp_mac_address(vname)
@@ -232,7 +269,9 @@ def guess_clone_name(request):
dhcp_file = "/srv/webvirtcloud/dhcpd.conf"
prefix = app_settings.CLONE_INSTANCE_DEFAULT_PREFIX
if os.path.isfile(dhcp_file):
- instance_names = [i.name for i in Instance.objects.filter(name__startswith=prefix)]
+ instance_names = [
+ i.name for i in Instance.objects.filter(name__startswith=prefix)
+ ]
with open(dhcp_file, "r") as f:
for line in f:
line = line.strip()
@@ -281,7 +320,11 @@ def get_instance(user, pk):
instance = get_object_or_404(Instance, pk=pk)
user_instances = user.userinstance_set.all().values_list("instance", flat=True)
- if user.is_superuser or user.has_perm("instances.view_instances") or instance.id in user_instances:
+ if (
+ user.is_superuser
+ or user.has_perm("instances.view_instances")
+ or instance.id in user_instances
+ ):
return instance
else:
raise Http404()
@@ -293,7 +336,9 @@ def poweron(request, pk):
messages.warning(request, _("Templates cannot be started."))
else:
instance.proxy.start()
- addlogmsg(request.user.username, instance.compute.name, instance.name, _("Power On"))
+ addlogmsg(
+ request.user.username, instance.compute.name, instance.name, _("Power On")
+ )
return redirect(request.META.get("HTTP_REFERER"))
@@ -302,14 +347,18 @@ def powercycle(request, pk):
instance = get_instance(request.user, pk)
instance.proxy.force_shutdown()
instance.proxy.start()
- addlogmsg(request.user.username, instance.compute.name, instance.name, _("Power Cycle"))
+ addlogmsg(
+ request.user.username, instance.compute.name, instance.name, _("Power Cycle")
+ )
return redirect(request.META.get("HTTP_REFERER"))
def poweroff(request, pk):
instance = get_instance(request.user, pk)
instance.proxy.shutdown()
- addlogmsg(request.user.username, instance.compute.name, instance.name, _("Power Off"))
+ addlogmsg(
+ request.user.username, instance.compute.name, instance.name, _("Power Off")
+ )
return redirect(request.META.get("HTTP_REFERER"))
@@ -333,7 +382,9 @@ def resume(request, pk):
def force_off(request, pk):
instance = get_instance(request.user, pk)
instance.proxy.force_shutdown()
- addlogmsg(request.user.username, instance.compute.name, instance.name, _("Force Off"))
+ addlogmsg(
+ request.user.username, instance.compute.name, instance.name, _("Force Off")
+ )
return redirect(request.META.get("HTTP_REFERER"))
@@ -349,7 +400,9 @@ def destroy(request, pk):
instance.proxy.force_shutdown()
if request.POST.get("delete_disk", ""):
- snapshots = sorted(instance.proxy.get_snapshot(), reverse=True, key=lambda k: k["date"])
+ snapshots = sorted(
+ instance.proxy.get_snapshot(), reverse=True, key=lambda k: k["date"]
+ )
for snapshot in snapshots:
instance.proxy.snapshot_delete(snapshot["name"])
instance.proxy.delete_all_disks()
@@ -360,7 +413,9 @@ def destroy(request, pk):
instance.proxy.delete(VIR_DOMAIN_UNDEFINE_KEEP_NVRAM)
instance.delete()
- addlogmsg(request.user.username, instance.compute.name, instance.name, _("Destroy"))
+ addlogmsg(
+ request.user.username, instance.compute.name, instance.name, _("Destroy")
+ )
return redirect(reverse("instances:index"))
return render(
@@ -390,12 +445,26 @@ def migrate(request, pk):
target_host = Compute.objects.get(id=compute_id)
try:
- utils.migrate_instance(target_host, instance, request.user, live, unsafe, xml_del, offline, autoconverge, compress, postcopy)
+ utils.migrate_instance(
+ target_host,
+ instance,
+ request.user,
+ live,
+ unsafe,
+ xml_del,
+ offline,
+ autoconverge,
+ compress,
+ postcopy,
+ )
except libvirtError as err:
messages.error(request, err)
migration_method = "live" if live is True else "offline"
- msg = _("Instance is migrated(%(method)s) to %(hostname)s") % {"hostname": target_host.hostname, "method": migration_method}
+ msg = _("Instance is migrated(%(method)s) to %(hostname)s") % {
+ "hostname": target_host.hostname,
+ "method": migration_method,
+ }
addlogmsg(request.user.username, current_host, instance.name, msg)
return redirect(request.META.get("HTTP_REFERER"))
@@ -419,7 +488,9 @@ def set_root_pass(request, pk):
s.close()
if result["return"] == "success":
msg = _("Reset root password")
- addlogmsg(request.user.username, instance.compute.name, instance.name, msg)
+ addlogmsg(
+ request.user.username, instance.compute.name, instance.name, msg
+ )
messages.success(request, msg)
else:
messages.error(request, result["message"])
@@ -434,7 +505,11 @@ def add_public_key(request, pk):
if request.method == "POST":
sshkeyid = request.POST.get("sshkeyid", "")
publickey = UserSSHKey.objects.get(id=sshkeyid)
- data = {"action": "publickey", "key": publickey.keypublic, "vname": instance.name}
+ data = {
+ "action": "publickey",
+ "key": publickey.keypublic,
+ "vname": instance.name,
+ }
if instance.proxy.get_status() == 5:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -445,7 +520,9 @@ def add_public_key(request, pk):
if result["return"] == "error":
msg = result["message"]
else:
- msg = _("Installed new SSH public key %(keyname)s") % {"keyname": publickey.keyname}
+ msg = _("Installed new SSH public key %(keyname)s") % {
+ "keyname": publickey.keyname
+ }
addlogmsg(request.user.username, instance.compute.name, instance.name, msg)
if result["return"] == "success":
@@ -470,9 +547,13 @@ def resizevm_cpu(request, pk):
new_vcpu = request.POST.get("vcpu", "")
new_cur_vcpu = request.POST.get("cur_vcpu", "")
- quota_msg = utils.check_user_quota(request.user, 0, int(new_vcpu) - vcpu, 0, 0)
+ quota_msg = utils.check_user_quota(
+ request.user, 0, int(new_vcpu) - vcpu, 0, 0
+ )
if not request.user.is_superuser and quota_msg:
- msg = _("User %(quota_msg)s quota reached, cannot resize CPU of '%(instance_name)s'!") % {
+ msg = _(
+ "User %(quota_msg)s quota reached, cannot resize CPU of '%(instance_name)s'!"
+ ) % {
"quota_msg": quota_msg,
"instance_name": instance.name,
}
@@ -481,8 +562,13 @@ def resizevm_cpu(request, pk):
cur_vcpu = new_cur_vcpu
vcpu = new_vcpu
instance.proxy.resize_cpu(cur_vcpu, vcpu)
- msg = _("CPU is resized: %(old)s to %(new)s") % {"old": cur_vcpu, "new": vcpu}
- addlogmsg(request.user.username, instance.compute.name, instance.name, msg)
+ msg = _("CPU is resized: %(old)s to %(new)s") % {
+ "old": cur_vcpu,
+ "new": vcpu,
+ }
+ addlogmsg(
+ request.user.username, instance.compute.name, instance.name, msg
+ )
messages.success(request, msg)
return redirect(reverse("instances:instance", args=[instance.id]) + "#resize")
@@ -507,22 +593,30 @@ def resize_memory(request, pk):
new_cur_memory_custom = request.POST.get("cur_memory_custom", "")
if new_cur_memory_custom:
new_cur_memory = new_cur_memory_custom
- quota_msg = utils.check_user_quota(request.user, 0, 0, int(new_memory) - memory, 0)
+ quota_msg = utils.check_user_quota(
+ request.user, 0, 0, int(new_memory) - memory, 0
+ )
if not request.user.is_superuser and quota_msg:
- msg = _("User %(quota_msg)s quota reached, cannot resize memory of '%(instance_name)s'!") % {
+ msg = _(
+ "User %(quota_msg)s quota reached, cannot resize memory of '%(instance_name)s'!"
+ ) % {
"quota_msg": quota_msg,
"instance_name": instance.name,
}
messages.error(request, msg)
else:
instance.proxy.resize_mem(new_cur_memory, new_memory)
- msg = _("Memory is resized: current/max: %(old_cur)s/%(old_max)s to %(new_cur)s/%(new_max)s") % {
+ msg = _(
+ "Memory is resized: current/max: %(old_cur)s/%(old_max)s to %(new_cur)s/%(new_max)s"
+ ) % {
"old_cur": cur_memory,
"old_max": memory,
"new_cur": new_cur_memory,
"new_max": new_memory,
}
- addlogmsg(request.user.username, instance.compute.name, instance.name, msg)
+ addlogmsg(
+ request.user.username, instance.compute.name, instance.name, msg
+ )
messages.success(request, msg)
return redirect(reverse("instances:instance", args=[instance.id]) + "#resize")
@@ -542,15 +636,21 @@ def resize_disk(request, pk):
if request.user.is_superuser or request.user.is_staff or userinstance.is_change:
disks_new = list()
for disk in disks:
- 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):
disk["size_new"] = input_disk_size
disks_new.append(disk)
disk_sum = sum([disk["size"] >> 30 for disk in disks_new])
disk_new_sum = sum([disk["size_new"] >> 30 for disk in disks_new])
- quota_msg = utils.check_user_quota(request.user, 0, 0, 0, disk_new_sum - disk_sum)
+ quota_msg = utils.check_user_quota(
+ request.user, 0, 0, 0, disk_new_sum - disk_sum
+ )
if not request.user.is_superuser and quota_msg:
- msg = _("User %(quota_msg)s quota reached, cannot resize disks of '%(instance_name)s'!") % {
+ msg = _(
+ "User %(quota_msg)s quota reached, cannot resize disks of '%(instance_name)s'!"
+ ) % {
"quota_msg": quota_msg,
"instance_name": instance.name,
}
@@ -558,7 +658,9 @@ def resize_disk(request, pk):
else:
instance.proxy.resize_disk(disks_new)
msg = _("Disk is resized: %(dev)s") % {"dev": disk["dev"]}
- addlogmsg(request.user.username, instance.compute.name, instance.name, msg)
+ addlogmsg(
+ request.user.username, instance.compute.name, instance.name, msg
+ )
messages.success(request, msg)
return redirect(reverse("instances:instance", args=[instance.id]) + "#resize")
@@ -566,7 +668,9 @@ def resize_disk(request, pk):
def add_new_vol(request, pk):
instance = get_instance(request.user, pk)
- 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
+ )
if allow_admin_or_not_template:
media = instance.proxy.get_media_devices()
@@ -607,20 +711,34 @@ def add_new_vol(request, pk):
pool_type = conn_pool.get_type()
disk_type = conn_pool.get_volume_type(os.path.basename(source))
- if pool_type == 'rbd':
+ if pool_type == "rbd":
source_info = conn_pool.get_rbd_source()
- else: # add more disk types to handle different pool and disk types
+ else: # add more disk types to handle different pool and disk types
source_info = None
- instance.proxy.attach_disk(target_dev, source, source_info=source_info, pool_type=pool_type, disk_type=disk_type, target_bus=bus, format_type=format, cache_mode=cache)
- msg = _("Attach new disk: %(name)s (%(format)s)") % {"name": name, "format": format}
+ instance.proxy.attach_disk(
+ target_dev,
+ source,
+ source_info=source_info,
+ pool_type=pool_type,
+ disk_type=disk_type,
+ target_bus=bus,
+ format_type=format,
+ cache_mode=cache,
+ )
+ msg = _("Attach new disk: %(name)s (%(format)s)") % {
+ "name": name,
+ "format": format,
+ }
addlogmsg(request.user.username, instance.compute.name, instance.name, msg)
return redirect(request.META.get("HTTP_REFERER") + "#disks")
def add_existing_vol(request, pk):
instance = get_instance(request.user, pk)
- 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
+ )
if allow_admin_or_not_template:
storage = request.POST.get("selected_storage", "")
name = request.POST.get("vols", "")
@@ -641,7 +759,7 @@ def add_existing_vol(request, pk):
format_type = conn_create.get_volume_format_type(name)
disk_type = conn_create.get_volume_type(name)
pool_type = conn_create.get_type()
- if pool_type == 'rbd':
+ if pool_type == "rbd":
source_info = conn_create.get_rbd_source()
path = conn_create.get_source_name()
else:
@@ -651,7 +769,16 @@ def add_existing_vol(request, pk):
target_dev = utils.get_new_disk_dev(media, disks, bus)
source = f"{path}/{name}"
- instance.proxy.attach_disk(target_dev, source, source_info=source_info, pool_type=pool_type, disk_type=disk_type, target_bus=bus, format_type=format_type, cache_mode=cache)
+ instance.proxy.attach_disk(
+ target_dev,
+ source,
+ source_info=source_info,
+ pool_type=pool_type,
+ disk_type=disk_type,
+ target_bus=bus,
+ format_type=format_type,
+ cache_mode=cache,
+ )
msg = _("Attach Existing disk: %(target_dev)s") % {"target_dev": target_dev}
addlogmsg(request.user.username, instance.compute.name, instance.name, msg)
return redirect(request.META.get("HTTP_REFERER") + "#disks")
@@ -659,7 +786,9 @@ def add_existing_vol(request, pk):
def edit_volume(request, pk):
instance = get_instance(request.user, pk)
- 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
+ )
if "edit_volume" in request.POST and allow_admin_or_not_template:
target_dev = request.POST.get("dev", "")
@@ -671,10 +800,16 @@ def edit_volume(request, pk):
new_bus = request.POST.get("vol_bus", bus)
serial = request.POST.get("vol_serial", "")
format = request.POST.get("vol_format", "")
- cache = request.POST.get("vol_cache", app_settings.INSTANCE_VOLUME_DEFAULT_CACHE)
+ cache = request.POST.get(
+ "vol_cache", app_settings.INSTANCE_VOLUME_DEFAULT_CACHE
+ )
io = request.POST.get("vol_io_mode", app_settings.INSTANCE_VOLUME_DEFAULT_IO)
- discard = request.POST.get("vol_discard_mode", app_settings.INSTANCE_VOLUME_DEFAULT_DISCARD)
- zeroes = request.POST.get("vol_detect_zeroes", app_settings.INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES)
+ discard = request.POST.get(
+ "vol_discard_mode", app_settings.INSTANCE_VOLUME_DEFAULT_DISCARD
+ )
+ zeroes = request.POST.get(
+ "vol_detect_zeroes", app_settings.INSTANCE_VOLUME_DEFAULT_DETECT_ZEROES
+ )
new_target_dev = utils.get_new_disk_dev(instance.media, instance.disks, new_bus)
if new_bus != bus:
@@ -710,7 +845,10 @@ def edit_volume(request, pk):
if not instance.proxy.get_status() == 5:
messages.success(
request,
- _("Volume changes are applied. " + "But it will be activated after shutdown"),
+ _(
+ "Volume changes are applied. "
+ + "But it will be activated after shutdown"
+ ),
)
else:
messages.success(request, _("Volume is changed successfully."))
@@ -722,7 +860,9 @@ def edit_volume(request, pk):
def delete_vol(request, pk):
instance = get_instance(request.user, pk)
- 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
+ )
if allow_admin_or_not_template:
storage = request.POST.get("storage", "")
conn_delete = wvmStorage(
@@ -746,7 +886,9 @@ def delete_vol(request, pk):
def detach_vol(request, pk):
instance = get_instance(request.user, pk)
- 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
+ )
if allow_admin_or_not_template:
dev = request.POST.get("dev", "")
@@ -760,11 +902,20 @@ def detach_vol(request, pk):
def add_cdrom(request, pk):
instance = get_instance(request.user, pk)
- 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
+ )
if allow_admin_or_not_template:
bus = request.POST.get("bus", "ide" if instance.machine == "pc" else "sata")
target = utils.get_new_disk_dev(instance.media, instance.disks, bus)
- instance.proxy.attach_disk(target, "", disk_device="cdrom", cache_mode="none", target_bus=bus, readonly=True)
+ instance.proxy.attach_disk(
+ target,
+ "",
+ disk_device="cdrom",
+ cache_mode="none",
+ target_bus=bus,
+ readonly=True,
+ )
msg = _("Add CD-ROM: %(target)s") % {"target": target}
addlogmsg(request.user.username, instance.compute.name, instance.name, msg)
@@ -773,7 +924,9 @@ def add_cdrom(request, pk):
def detach_cdrom(request, pk, dev):
instance = get_instance(request.user, pk)
- 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
+ )
if allow_admin_or_not_template:
# dev = request.POST.get('detach_cdrom', '')
@@ -786,7 +939,9 @@ def detach_cdrom(request, pk, dev):
def unmount_iso(request, pk):
instance = get_instance(request.user, pk)
- 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
+ )
if allow_admin_or_not_template:
image = request.POST.get("path", "")
dev = request.POST.get("umount_iso", "")
@@ -799,7 +954,9 @@ def unmount_iso(request, pk):
def mount_iso(request, pk):
instance = get_instance(request.user, pk)
- 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
+ )
if allow_admin_or_not_template:
image = request.POST.get("media", "")
dev = request.POST.get("mount_iso", "")
@@ -812,9 +969,13 @@ def mount_iso(request, pk):
def snapshot(request, pk):
instance = get_instance(request.user, pk)
- 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
+ )
- if allow_admin_or_not_template and request.user.has_perm("instances.snapshot_instances"):
+ if allow_admin_or_not_template and request.user.has_perm(
+ "instances.snapshot_instances"
+ ):
name = request.POST.get("name", "")
desc = request.POST.get("description", "")
instance.proxy.create_snapshot(name, desc)
@@ -825,8 +986,12 @@ def snapshot(request, pk):
def delete_snapshot(request, pk):
instance = get_instance(request.user, pk)
- allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template
- if allow_admin_or_not_template and request.user.has_perm("instances.snapshot_instances"):
+ allow_admin_or_not_template = (
+ request.user.is_superuser or request.user.is_staff or not instance.is_template
+ )
+ if allow_admin_or_not_template and request.user.has_perm(
+ "instances.snapshot_instances"
+ ):
snap_name = request.POST.get("name", "")
instance.proxy.snapshot_delete(snap_name)
msg = _("Delete snapshot: %(snap)s") % {"snap": snap_name}
@@ -836,8 +1001,12 @@ def delete_snapshot(request, pk):
def revert_snapshot(request, pk):
instance = get_instance(request.user, pk)
- allow_admin_or_not_template = request.user.is_superuser or request.user.is_staff or not instance.is_template
- if allow_admin_or_not_template and request.user.has_perm("instances.snapshot_instances"):
+ allow_admin_or_not_template = (
+ request.user.is_superuser or request.user.is_staff or not instance.is_template
+ )
+ if allow_admin_or_not_template and request.user.has_perm(
+ "instances.snapshot_instances"
+ ):
snap_name = request.POST.get("name", "")
instance.proxy.snapshot_revert(snap_name)
msg = _("Successful revert snapshot: ")
@@ -865,7 +1034,7 @@ def set_vcpu(request, pk):
@superuser_only
def set_vcpu_hotplug(request, pk):
instance = get_instance(request.user, pk)
- status = True if request.POST.get("vcpu_hotplug", "False") == 'True' else False
+ status = True if request.POST.get("vcpu_hotplug", "False") == "True" else False
msg = _("VCPU Hot-plug is enabled=%(status)s") % {"status": status}
instance.proxy.set_vcpu_hotplug(status)
addlogmsg(request.user.username, instance.compute.name, instance.name, msg)
@@ -923,7 +1092,10 @@ def set_bootorder(request, pk):
if not instance.proxy.get_status() == 5:
messages.success(
request,
- _("Boot menu changes applied. " + "But it will be activated after shutdown"),
+ _(
+ "Boot menu changes applied. "
+ + "But it will be activated after shutdown"
+ ),
)
else:
messages.success(request, _("Boot order changed successfully."))
@@ -979,7 +1151,7 @@ def change_network(request, pk):
network_data[post] = source
network_data[post + "-type"] = source_type
- if source_type == 'iface':
+ if source_type == "iface":
iface = wvmInterface(
instance.compute.hostname,
instance.compute.login,
@@ -1007,14 +1179,14 @@ def add_network(request, pk):
nwfilter = request.POST.get("add-net-nwfilter")
(source, source_type) = utils.get_network_tuple(request.POST.get("add-net-network"))
- if source_type == 'iface':
+ if source_type == "iface":
iface = wvmInterface(
- instance.compute.hostname,
- instance.compute.login,
- instance.compute.password,
- instance.compute.type,
- source,
- )
+ instance.compute.hostname,
+ instance.compute.login,
+ instance.compute.password,
+ instance.compute.type,
+ source,
+ )
source_type = iface.get_type()
instance.proxy.add_network(mac, source, source_type, nwfilter=nwfilter)
@@ -1062,7 +1234,9 @@ def set_qos(request, pk):
instance.proxy.set_qos(mac, qos_dir, average, peak, burst)
if instance.proxy.get_status() == 5:
- messages.success(request, _("%(qos_dir)s QoS is set") % {"qos_dir": qos_dir.capitalize()})
+ messages.success(
+ request, _("%(qos_dir)s QoS is set") % {"qos_dir": qos_dir.capitalize()}
+ )
else:
messages.success(
request,
@@ -1084,7 +1258,9 @@ def unset_qos(request, pk):
instance.proxy.unset_qos(mac, qos_dir)
if instance.proxy.get_status() == 5:
- messages.success(request, _("%(qos_dir)s QoS is deleted") % {"qos_dir": qos_dir.capitalize()})
+ messages.success(
+ request, _("%(qos_dir)s QoS is deleted") % {"qos_dir": qos_dir.capitalize()}
+ )
else:
messages.success(
request,
@@ -1108,7 +1284,9 @@ def add_owner(request, pk):
check_inst = UserInstance.objects.filter(instance=instance).count()
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:
add_user_inst = UserInstance(instance=instance, user_id=user_id)
add_user_inst.save()
@@ -1137,7 +1315,9 @@ def clone(request, pk):
clone_data["name"] = request.POST.get("name", "")
disk_sum = sum([disk["size"] >> 30 for disk in instance.disks])
- quota_msg = utils.check_user_quota(request.user, 1, instance.vcpu, instance.memory, disk_sum)
+ quota_msg = utils.check_user_quota(
+ request.user, 1, instance.vcpu, instance.memory, disk_sum
+ )
check_instance = Instance.objects.filter(name=clone_data["name"])
clone_data["disk_owner_uid"] = int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_UID)
@@ -1156,19 +1336,31 @@ def clone(request, pk):
clone_data[disk_dev] = disk_name
if not request.user.is_superuser and quota_msg:
- msg = _("User '%(quota_msg)s' quota reached, cannot create '%(clone_name)s'!") % {
+ msg = _(
+ "User '%(quota_msg)s' quota reached, cannot create '%(clone_name)s'!"
+ ) % {
"quota_msg": quota_msg,
"clone_name": clone_data["name"],
}
messages.error(request, msg)
elif check_instance:
- msg = _("Instance '%(clone_name)s' already exists!") % {"clone_name": clone_data["name"]}
+ msg = _("Instance '%(clone_name)s' already exists!") % {
+ "clone_name": clone_data["name"]
+ }
messages.error(request, msg)
elif not re.match(r"^[a-zA-Z0-9-]+$", clone_data["name"]):
- msg = _("Instance name '%(clone_name)s' contains invalid characters!") % {"clone_name": clone_data["name"]}
+ msg = _("Instance name '%(clone_name)s' contains invalid characters!") % {
+ "clone_name": clone_data["name"]
+ }
messages.error(request, msg)
- elif not re.match(r"^([0-9A-F]{2})(:?[0-9A-F]{2}){5}$", clone_data["clone-net-mac-0"], re.IGNORECASE):
- msg = _("Instance MAC '%(clone_mac)s' invalid format!") % {"clone_mac": clone_data["clone-net-mac-0"]}
+ elif not re.match(
+ r"^([0-9A-F]{2})(:?[0-9A-F]{2}){5}$",
+ clone_data["clone-net-mac-0"],
+ re.IGNORECASE,
+ ):
+ msg = _("Instance MAC '%(clone_mac)s' invalid format!") % {
+ "clone_mac": clone_data["clone-net-mac-0"]
+ }
messages.error(request, msg)
else:
new_instance = Instance(compute=instance.compute, name=clone_data["name"])
@@ -1176,15 +1368,23 @@ def clone(request, pk):
new_uuid = instance.proxy.clone_instance(clone_data)
new_instance.uuid = new_uuid
new_instance.save()
- user_instance = UserInstance(instance_id=new_instance.id, user_id=request.user.id, is_delete=True)
+ user_instance = UserInstance(
+ instance_id=new_instance.id, user_id=request.user.id, is_delete=True
+ )
user_instance.save()
- msg = _("Create a clone of '%(instance_name)s'") % {"instance_name": instance.name}
+ msg = _("Create a clone of '%(instance_name)s'") % {
+ "instance_name": instance.name
+ }
messages.success(request, msg)
- addlogmsg(request.user.username, instance.compute.name, new_instance.name, msg)
+ addlogmsg(
+ request.user.username, instance.compute.name, new_instance.name, msg
+ )
if app_settings.CLONE_INSTANCE_AUTO_MIGRATE == "True":
new_compute = Compute.objects.order_by("?").first()
- utils.migrate_instance(new_compute, new_instance, request.user, xml_del=True, offline=True)
+ utils.migrate_instance(
+ new_compute, new_instance, request.user, xml_del=True, offline=True
+ )
return redirect(reverse("instances:instance", args=[new_instance.id]))
except Exception as e:
@@ -1223,7 +1423,9 @@ def update_console(request, pk):
messages.error(request, msg)
else:
msg = _("Set VNC password")
- addlogmsg(request.user.username, instance.compute.name, instance.name, msg)
+ addlogmsg(
+ request.user.username, instance.compute.name, instance.name, msg
+ )
if "keymap" in form.changed_data or "clear_keymap" in form.changed_data:
if form.cleaned_data["clear_keymap"]:
@@ -1232,17 +1434,23 @@ def update_console(request, pk):
instance.proxy.set_console_keymap(form.cleaned_data["keymap"])
msg = _("Set VNC keymap")
- addlogmsg(request.user.username, instance.compute.name, instance.name, msg)
+ addlogmsg(
+ request.user.username, instance.compute.name, instance.name, msg
+ )
if "type" in form.changed_data:
instance.proxy.set_console_type(form.cleaned_data["type"])
msg = _("Set VNC type")
- addlogmsg(request.user.username, instance.compute.name, instance.name, msg)
+ addlogmsg(
+ request.user.username, instance.compute.name, instance.name, msg
+ )
if "listen_on" in form.changed_data:
instance.proxy.set_console_listener_addr(form.cleaned_data["listen_on"])
msg = _("Set VNC listen address")
- addlogmsg(request.user.username, instance.compute.name, instance.name, msg)
+ addlogmsg(
+ request.user.username, instance.compute.name, instance.name, msg
+ )
return redirect(request.META.get("HTTP_REFERER") + "#vncsettings")
@@ -1326,7 +1534,15 @@ 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"]
+ supported_arch = [
+ "x86_64",
+ "i686",
+ "aarch64",
+ "armv7l",
+ "ppc64",
+ "ppc64le",
+ "s390x",
+ ]
hypervisors = [hpv for hpv in all_hypervisors.keys() if hpv in supported_arch]
default_machine = app_settings.INSTANCE_MACHINE_DEFAULT_TYPE
default_arch = app_settings.INSTANCE_ARCH_DEFAULT_TYPE
@@ -1371,7 +1587,12 @@ def create_instance(request, compute_id, arch, machine):
appsettings = AppSettings.objects.all()
try:
- conn = wvmCreate(compute.hostname, compute.login, compute.password, compute.type)
+ conn = wvmCreate(
+ compute.hostname,
+ compute.login,
+ compute.password,
+ compute.type
+ )
default_firmware = app_settings.INSTANCE_FIRMWARE_DEFAULT_TYPE
default_cpu_mode = app_settings.INSTANCE_CPU_DEFAULT_MODE
@@ -1397,7 +1618,7 @@ def create_instance(request, compute_id, arch, machine):
storages = sorted(conn.get_storages(only_actives=True))
default_graphics = app_settings.QEMU_CONSOLE_DEFAULT_TYPE
default_cdrom = app_settings.INSTANCE_CDROM_ADD
- input_device_buses = ['default', 'virtio', 'usb']
+ input_device_buses = ["default", "virtio", "usb"]
default_input_device_bus = app_settings.INSTANCE_INPUT_DEFAULT_DEVICE
dom_caps = conn.get_dom_capabilities(arch, machine)
@@ -1437,13 +1658,21 @@ def create_instance(request, compute_id, arch, machine):
meta_prealloc = True
if instances:
if data["name"] in instances:
- raise libvirtError(_("A virtual machine with this name already exists"))
+ raise libvirtError(
+ _("A virtual machine with this name already exists")
+ )
if Instance.objects.filter(name__exact=data["name"]):
- raise libvirtError(_("There is an instance with same name. Remove it and try again!"))
+ raise libvirtError(
+ _(
+ "There is an instance with same name. Remove it and try again!"
+ )
+ )
if data["hdd_size"]:
if not data["mac"]:
- raise libvirtError(_("No Virtual Machine MAC has been entered"))
+ raise libvirtError(
+ _("No Virtual Machine MAC has been entered")
+ )
else:
path = conn.create_volume(
data["storage"],
@@ -1471,10 +1700,14 @@ def create_instance(request, compute_id, arch, machine):
elif data["template"]:
templ_path = conn.get_volume_path(data["template"])
- dest_vol = conn.get_volume_path(data["name"] + ".img", data["storage"])
+ dest_vol = conn.get_volume_path(
+ data["name"] + ".img", data["storage"]
+ )
if dest_vol:
raise libvirtError(
- _("Image has already exist. Please check volumes or change instance name")
+ _(
+ "Image has already exist. Please check volumes or change instance name"
+ )
)
else:
clone_path = conn.clone_from_template(
@@ -1501,15 +1734,21 @@ def create_instance(request, compute_id, arch, machine):
is_disk_created = True
else:
if not data["images"]:
- raise libvirtError(_("First you need to create or select an image"))
+ raise libvirtError(
+ _("First you need to create or select an image")
+ )
else:
for idx, vol in enumerate(data["images"].split(",")):
path = conn.get_volume_path(vol)
volume = dict()
volume["path"] = path
volume["type"] = conn.get_volume_format_type(path)
- volume["device"] = request.POST.get("device" + str(idx), "")
- volume["bus"] = request.POST.get("bus" + str(idx), "")
+ volume["device"] = request.POST.get(
+ "device" + str(idx), ""
+ )
+ volume["bus"] = request.POST.get(
+ "bus" + str(idx), ""
+ )
if volume["bus"] == "scsi":
volume["scsi_model"] = default_scsi_disk_model
volume["cache_mode"] = data["cache_mode"]
@@ -1560,12 +1799,21 @@ def create_instance(request, compute_id, arch, machine):
add_cdrom=data["add_cdrom"],
add_input=data["add_input"],
)
- create_instance = Instance(compute_id=compute_id, name=data["name"], uuid=uuid)
+ create_instance = Instance(
+ compute_id=compute_id, name=data["name"], uuid=uuid
+ )
create_instance.save()
msg = _("Instance is created")
messages.success(request, msg)
- addlogmsg(request.user.username, create_instance.compute.name, create_instance.name, msg)
- return redirect(reverse("instances:instance", args=[create_instance.id]))
+ addlogmsg(
+ request.user.username,
+ create_instance.compute.name,
+ create_instance.name,
+ msg,
+ )
+ return redirect(
+ reverse("instances:instance", args=[create_instance.id])
+ )
except libvirtError as lib_err:
if data["hdd_size"] or len(volume_list) > 0:
if is_disk_created:
diff --git a/interfaces/forms.py b/interfaces/forms.py
index c19ffda..90c4ee0 100644
--- a/interfaces/forms.py
+++ b/interfaces/forms.py
@@ -7,13 +7,33 @@ from django.utils.translation import gettext_lazy as _
class AddInterface(forms.Form):
name = forms.CharField(max_length=10, required=True)
itype = forms.ChoiceField(required=True, choices=(('bridge', 'bridge'), ('ethernet', 'ethernet')))
- start_mode = forms.ChoiceField(required=True,
- choices=(('none', 'none'), ('onboot', 'onboot'), ('hotplug', 'hotplug')))
+ start_mode = forms.ChoiceField(
+ required=True,
+ choices=(
+ ('none', 'none'),
+ ('onboot', 'onboot'),
+ ('hotplug', 'hotplug')
+ )
+ )
netdev = forms.CharField(max_length=15, required=True)
- ipv4_type = forms.ChoiceField(required=True, choices=(('dhcp', 'dhcp'), ('static', 'static'), ('none', 'none')))
+ ipv4_type = forms.ChoiceField(
+ required=True,
+ choices=(
+ ('dhcp', 'dhcp'),
+ ('static', 'static'),
+ ('none', 'none')
+ )
+ )
ipv4_addr = forms.CharField(max_length=18, required=False)
ipv4_gw = forms.CharField(max_length=15, required=False)
- ipv6_type = forms.ChoiceField(required=True, choices=(('dhcp', 'dhcp'), ('static', 'static'), ('none', 'none')))
+ ipv6_type = forms.ChoiceField(
+ required=True,
+ choices=(
+ ('dhcp', 'dhcp'),
+ ('static', 'static'),
+ ('none', 'none')
+ )
+ )
ipv6_addr = forms.CharField(max_length=100, required=False)
ipv6_gw = forms.CharField(max_length=100, required=False)
stp = forms.ChoiceField(required=False, choices=(('on', 'on'), ('off', 'off')))
@@ -39,7 +59,7 @@ class AddInterface(forms.Form):
def clean_ipv6_addr(self):
ipv6_addr = self.cleaned_data['ipv6_addr']
- have_symbol = re.match('^[0-9a-f./:]+$', ipv6_addr)
+ have_symbol = re.match('^[0-9a-f./:]+|^$', ipv6_addr)
if not have_symbol:
raise forms.ValidationError(_('The IPv6 address must not contain any special characters'))
elif len(ipv6_addr) > 100:
@@ -48,7 +68,7 @@ class AddInterface(forms.Form):
def clean_ipv6_gw(self):
ipv6_gw = self.cleaned_data['ipv6_gw']
- have_symbol = re.match('^[0-9.]+$', ipv6_gw)
+ have_symbol = re.match('^[0-9a-f./:]+|^$', ipv6_gw)
if not have_symbol:
raise forms.ValidationError(_('The IPv6 gateway must not contain any special characters'))
elif len(ipv6_gw) > 100:
diff --git a/interfaces/models.py b/interfaces/models.py
index c2834e8..ff7d7eb 100644
--- a/interfaces/models.py
+++ b/interfaces/models.py
@@ -4,10 +4,14 @@ from django.utils.translation import gettext_lazy as _
# Create your models here.
class Interfaces(models.Model):
- name = models.CharField(_('name'), max_length=20, error_messages={'required': _('No interface name has been entered')})
- type = models.CharField(_('status'), max_length=12)
- state = models.CharField(_('device'), max_length=100)
- mac = models.CharField(_('forward'), max_length=24)
+ name = models.CharField(
+ _("name"),
+ max_length=20,
+ error_messages={"required": _("No interface name has been entered")},
+ )
+ type = models.CharField(_("status"), max_length=12)
+ state = models.CharField(_("device"), max_length=100)
+ mac = models.CharField(_("forward"), max_length=24)
class Meta:
managed = False
diff --git a/interfaces/templates/create_iface_block.html b/interfaces/templates/create_iface_block.html
index f5bb627..8583297 100644
--- a/interfaces/templates/create_iface_block.html
+++ b/interfaces/templates/create_iface_block.html
@@ -95,13 +95,13 @@
@@ -121,13 +121,13 @@
diff --git a/interfaces/views.py b/interfaces/views.py
index 0ef2cb6..36e9b3e 100644
--- a/interfaces/views.py
+++ b/interfaces/views.py
@@ -21,7 +21,12 @@ def interfaces(request, compute_id):
compute = get_object_or_404(Compute, pk=compute_id)
try:
- conn = wvmInterfaces(compute.hostname, compute.login, compute.password, compute.type)
+ conn = wvmInterfaces(
+ compute.hostname,
+ compute.login,
+ compute.password,
+ compute.type
+ )
ifaces = conn.get_ifaces()
try:
netdevs = conn.get_net_devices()
@@ -29,7 +34,13 @@ def interfaces(request, compute_id):
netdevs = ["eth0", "eth1"]
for iface in ifaces:
- interf = wvmInterface(compute.hostname, compute.login, compute.password, compute.type, iface)
+ interf = wvmInterface(
+ compute.hostname,
+ compute.login,
+ compute.password,
+ compute.type,
+ iface
+ )
ifaces_all.append(interf.get_details())
if request.method == "POST":
@@ -75,7 +86,13 @@ def interface(request, compute_id, iface):
compute = get_object_or_404(Compute, pk=compute_id)
try:
- conn = wvmInterface(compute.hostname, compute.login, compute.password, compute.type, iface)
+ conn = wvmInterface(
+ compute.hostname,
+ compute.login,
+ compute.password,
+ compute.type,
+ iface
+ )
start_mode = conn.get_start_mode()
state = conn.is_active()
mac = conn.get_mac()
diff --git a/networks/api/serializers.py b/networks/api/serializers.py
index 347d1db..61f5a8d 100644
--- a/networks/api/serializers.py
+++ b/networks/api/serializers.py
@@ -1,12 +1,8 @@
-
from rest_framework import serializers
from networks.models import Networks
class NetworksSerializer(serializers.ModelSerializer):
-
class Meta:
model = Networks
- fields = ['name', 'status', 'device', 'forward']
-
-
+ fields = ["name", "status", "device", "forward"]
diff --git a/networks/forms.py b/networks/forms.py
index 36ceed9..5c014cf 100644
--- a/networks/forms.py
+++ b/networks/forms.py
@@ -5,7 +5,10 @@ from django.utils.translation import gettext_lazy as _
class AddNetPool(forms.Form):
- name = forms.CharField(error_messages={"required": _("No pool name has been entered")}, max_length=20)
+ name = forms.CharField(
+ error_messages={"required": _("No pool name has been entered")},
+ max_length=20
+ )
subnet = forms.CharField(
error_messages={"required": _("No IPv4 subnet has been entered")},
max_length=20,
@@ -27,27 +30,39 @@ class AddNetPool(forms.Form):
name = self.cleaned_data["name"]
have_symbol = re.match(r"^[a-zA-Z0-9\.\_\-]+$", name)
if not have_symbol:
- raise forms.ValidationError(_("The pool name must not contain any special characters"))
+ raise forms.ValidationError(
+ _("The pool name must not contain any special characters")
+ )
elif len(name) > 20:
- raise forms.ValidationError(_("The pool name must not exceed 20 characters"))
+ raise forms.ValidationError(
+ _("The pool name must not exceed 20 characters")
+ )
return name
def clean_subnet(self):
subnet = self.cleaned_data["subnet"]
have_symbol = re.match("^[0-9./]+$", subnet if subnet else ".")
if not have_symbol:
- raise forms.ValidationError(_("The IPv4 subnet must not contain any special characters"))
+ raise forms.ValidationError(
+ _("The IPv4 subnet must not contain any special characters")
+ )
elif len(subnet) > 20:
- raise forms.ValidationError(_("The IPv4 subnet must not exceed 20 characters"))
+ raise forms.ValidationError(
+ _("The IPv4 subnet must not exceed 20 characters")
+ )
return subnet
def clean_subnet6(self):
subnet = self.cleaned_data["subnet6"]
have_symbol = re.match("^[0-9a-fA-F:/]+$", subnet if subnet else ":")
if not have_symbol:
- raise forms.ValidationError(_("The IPv6 subnet must not contain any special characters"))
+ raise forms.ValidationError(
+ _("The IPv6 subnet must not contain any special characters")
+ )
elif len(subnet) > 42:
- raise forms.ValidationError(_("The IPv6 subnet must not exceed 42 characters"))
+ raise forms.ValidationError(
+ _("The IPv6 subnet must not exceed 42 characters")
+ )
return subnet
def clean_bridge_name(self):
@@ -55,7 +70,11 @@ class AddNetPool(forms.Form):
if self.cleaned_data["forward"] in ["bridge", "macvtap"]:
have_symbol = re.match(r"^[a-zA-Z0-9\.\_\:\-]+$", bridge_name)
if not have_symbol:
- raise forms.ValidationError(_("The pool bridge name must not contain any special characters"))
+ raise forms.ValidationError(
+ _("The pool bridge name must not contain any special characters")
+ )
elif len(bridge_name) > 20:
- raise forms.ValidationError(_("The pool bridge name must not exceed 20 characters"))
+ raise forms.ValidationError(
+ _("The pool bridge name must not exceed 20 characters")
+ )
return bridge_name
diff --git a/networks/models.py b/networks/models.py
index c52ceff..0f272bf 100644
--- a/networks/models.py
+++ b/networks/models.py
@@ -4,10 +4,14 @@ from django.utils.translation import gettext_lazy as _
# Create your models here.
class Networks(models.Model):
- name = models.CharField(_('name'), max_length=20, error_messages={'required': _('No network name has been entered')})
- status = models.CharField(_('status'), max_length=12)
- device = models.CharField(_('device'), max_length=100)
- forward = models.CharField(_('forward'), max_length=24)
+ name = models.CharField(
+ _("name"),
+ max_length=20,
+ error_messages={"required": _("No network name has been entered")},
+ )
+ status = models.CharField(_("status"), max_length=12)
+ device = models.CharField(_("device"), max_length=100)
+ forward = models.CharField(_("forward"), max_length=24)
class Meta:
managed = False
diff --git a/networks/views.py b/networks/views.py
index f40a395..bb95741 100644
--- a/networks/views.py
+++ b/networks/views.py
@@ -43,18 +43,26 @@ def networks(request, compute_id):
msg = _("Network pool name already in use")
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"] == ""
+ ):
messages.error(request, _("Please enter bridge/dev name"))
errors = True
if data["subnet"]:
ipv4 = True
- gateway4, netmask4, dhcp4 = network_size(data["subnet"], data["dhcp4"])
+ gateway4, netmask4, dhcp4 = network_size(
+ data["subnet"], data["dhcp4"]
+ )
if data["subnet6"]:
ipv6 = True
- gateway6, prefix6, dhcp6 = network_size(data["subnet6"], data["dhcp6"])
+ gateway6, prefix6, dhcp6 = network_size(
+ data["subnet6"], data["dhcp6"]
+ )
if prefix6 != "64":
messages.error(
- request, _("For libvirt, the IPv6 network prefix must be /64")
+ request,
+ _("For libvirt, the IPv6 network prefix must be /64"),
)
errors = True
if not errors:
@@ -177,7 +185,11 @@ def network(request, compute_id, pool):
try:
ret_val = conn.modify_fixed_address(name, address, mac_duid, family)
- messages.success(request, _("Fixed address operation completed for %(family)s") % {"family": family.upper()})
+ messages.success(
+ request,
+ _("Fixed address operation completed for %(family)s")
+ % {"family": family.upper()},
+ )
return HttpResponseRedirect(request.get_full_path())
except libvirtError as lib_err:
messages.error(request, lib_err)
@@ -187,7 +199,10 @@ def network(request, compute_id, pool):
ip = request.POST.get("address", "")
family = request.POST.get("family", "ipv4")
conn.delete_fixed_address(ip, family)
- messages.success(request, _("%(family)s Fixed Address is Deleted.") % {"family": family.upper()})
+ messages.success(
+ request,
+ _("%(family)s Fixed Address is Deleted.") % {"family": family.upper()},
+ )
return HttpResponseRedirect(request.get_full_path())
if "modify_dhcp_range" in request.POST:
range_start = request.POST.get("range_start", "")
@@ -195,7 +210,10 @@ def network(request, compute_id, pool):
family = request.POST.get("family", "ipv4")
try:
conn.modify_dhcp_range(range_start, range_end, family)
- messages.success(request, _("%(family)s DHCP Range is Changed.") % {"family": family.upper()})
+ messages.success(
+ request,
+ _("%(family)s DHCP Range is Changed.") % {"family": family.upper()},
+ )
return HttpResponseRedirect(request.get_full_path())
except libvirtError as lib_err:
messages.error(request, lib_err)
@@ -225,10 +243,16 @@ def network(request, compute_id, pool):
if conn.is_active():
messages.success(
request,
- _("%(qos_dir)s QoS is updated. Network XML is changed. Stop and start network to activate new config") % {"qos_dir": qos_dir.capitalize()}
+ _(
+ "%(qos_dir)s QoS is updated. Network XML is changed. Stop and start network to activate new config"
+ )
+ % {"qos_dir": qos_dir.capitalize()},
)
else:
- messages.success(request, _("%(qos_dir)s QoS is set") % {"qos_dir": qos_dir.capitalize()})
+ messages.success(
+ request,
+ _("%(qos_dir)s QoS is set") % {"qos_dir": qos_dir.capitalize()},
+ )
except libvirtError as lib_err:
messages.error(request, lib_err)
return HttpResponseRedirect(request.get_full_path())
@@ -239,11 +263,17 @@ def network(request, compute_id, pool):
if conn.is_active():
messages.success(
request,
- _("%(qos_dir)s QoS is deleted. Network XML is changed. \
- Stop and start network to activate new config") % {"qos_dir": qos_dir.capitalize()}
+ _(
+ "%(qos_dir)s QoS is deleted. Network XML is changed. \
+ Stop and start network to activate new config"
+ )
+ % {"qos_dir": qos_dir.capitalize()},
)
else:
- messages.success(request, _("%(qos_dir)s QoS is deleted") % {"qos_dir": qos_dir.capitalize()})
+ messages.success(
+ request,
+ _("%(qos_dir)s QoS is deleted") % {"qos_dir": qos_dir.capitalize()},
+ )
return HttpResponseRedirect(request.get_full_path())
conn.close()
diff --git a/nwfilters/views.py b/nwfilters/views.py
index 527f391..6651450 100644
--- a/nwfilters/views.py
+++ b/nwfilters/views.py
@@ -23,7 +23,12 @@ def nwfilters(request, compute_id):
compute = get_object_or_404(Compute, pk=compute_id)
try:
- conn = wvmNWFilters(compute.hostname, compute.login, compute.password, compute.type)
+ conn = wvmNWFilters(
+ compute.hostname,
+ compute.login,
+ compute.password,
+ compute.type
+ )
for nwf in conn.get_nwfilters():
nwfilters_all.append(conn.get_nwfilter_info(nwf))
@@ -41,19 +46,27 @@ def nwfilters(request, compute_id):
for nwf in nwfilters_all:
if name == nwf["name"]:
- error_msg = _("A network filter with this name already exists")
+ error_msg = _(
+ "A network filter with this name already exists"
+ )
raise Exception(error_msg)
if uuid == nwf["uuid"]:
- error_msg = _("A network filter with this UUID already exists")
+ error_msg = _(
+ "A network filter with this UUID already exists"
+ )
raise Exception(error_msg)
else:
try:
- msg = _("%(filter)s network filter is created") % {"filter": name}
+ msg = _("%(filter)s network filter is created") % {
+ "filter": name
+ }
conn.create_nwfilter(xml)
addlogmsg(request.user.username, compute.hostname, "", msg)
except libvirtError as 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:
name = request.POST.get("nwfiltername", "")
@@ -63,18 +76,27 @@ def nwfilters(request, compute_id):
nwfilter_info = conn.get_nwfilter_info(name)
is_conn = wvmInstances(
- compute.hostname, compute.login, compute.password, compute.type
+ compute.hostname,
+ compute.login,
+ compute.password,
+ compute.type
)
instances = is_conn.get_instances()
for inst in instances:
i_conn = wvmInstance(
- compute.hostname, compute.login, compute.password, compute.type, inst
+ compute.hostname,
+ compute.login,
+ compute.password,
+ compute.type,
+ inst,
)
dom_filterrefs = i_conn.get_filterrefs()
if name in dom_filterrefs:
in_use = True
- msg = _("NWFilter is in use by %(instance)s. Cannot be deleted.") % {"instance": inst}
+ msg = _(
+ "NWFilter is in use by %(instance)s. Cannot be deleted."
+ ) % {"instance": inst}
messages.error(request, msg)
addlogmsg(request.user.username, compute.hostname, "", msg)
i_conn.close()
@@ -93,7 +115,10 @@ def nwfilters(request, compute_id):
conn.clone_nwfilter(name, cln_name)
nwfilters_all.append(conn.get_nwfilter_info(cln_name))
- msg = _("Cloning NWFilter %(name)s as %(clone)s") % {"name":name, "clone": cln_name}
+ msg = _("Cloning NWFilter %(name)s as %(clone)s") % {
+ "name": name,
+ "clone": cln_name,
+ }
addlogmsg(request.user.username, compute.hostname, "", msg)
conn.close()
@@ -126,9 +151,18 @@ def nwfilter(request, compute_id, nwfltr):
try:
nwfilter = wvmNWFilter(
- compute.hostname, compute.login, compute.password, compute.type, nwfltr
+ compute.hostname,
+ compute.login,
+ compute.password,
+ compute.type,
+ nwfltr
+ )
+ conn = wvmNWFilters(
+ compute.hostname,
+ compute.login,
+ compute.password,
+ compute.type
)
- conn = wvmNWFilters(compute.hostname, compute.login, compute.password, compute.type)
for nwf in conn.get_nwfilters():
nwfilters_all.append(conn.get_nwfilter_info(nwf))
diff --git a/storages/forms.py b/storages/forms.py
index 64dcd3c..bb1858c 100644
--- a/storages/forms.py
+++ b/storages/forms.py
@@ -5,9 +5,15 @@ from django.utils.translation import gettext_lazy as _
class AddStgPool(forms.Form):
- name = forms.CharField(error_messages={'required': _('No pool name has been entered')}, max_length=20)
+ name = forms.CharField(
+ error_messages={"required": _("No pool name has been entered")}, max_length=20
+ )
stg_type = forms.CharField(max_length=10)
- target = forms.CharField(error_messages={'required': _('No path has been entered')}, max_length=100, required=False)
+ target = forms.CharField(
+ error_messages={"required": _("No path has been entered")},
+ max_length=100,
+ required=False,
+ )
source = forms.CharField(max_length=100, required=False)
ceph_user = forms.CharField(required=False)
ceph_host = forms.CharField(required=False)
@@ -17,49 +23,62 @@ class AddStgPool(forms.Form):
source_format = forms.CharField(required=False)
def clean_name(self):
- name = self.cleaned_data['name']
- have_symbol = re.match('^[a-zA-Z0-9._-]+$', name)
+ name = self.cleaned_data["name"]
+ have_symbol = re.match("^[a-zA-Z0-9._-]+$", name)
if not have_symbol:
- raise forms.ValidationError(_('The pool name must not contain any special characters'))
+ raise forms.ValidationError(
+ _("The pool name must not contain any special characters")
+ )
elif len(name) > 20:
- raise forms.ValidationError(_('The pool name must not exceed 20 characters'))
+ raise forms.ValidationError(
+ _("The pool name must not exceed 20 characters")
+ )
return name
def clean_target(self):
- storage_type = self.cleaned_data['stg_type']
- target = self.cleaned_data['target']
- have_symbol = re.match('^[a-zA-Z0-9/]+$', target)
- if storage_type == 'dir' or storage_type == 'netfs':
+ storage_type = self.cleaned_data["stg_type"]
+ target = self.cleaned_data["target"]
+ have_symbol = re.match("^[a-zA-Z0-9/]+$", target)
+ if storage_type == "dir" or storage_type == "netfs":
if not have_symbol:
- raise forms.ValidationError(_('The target must not contain any special characters'))
- if storage_type == 'dir' or storage_type == 'netfs':
+ raise forms.ValidationError(
+ _("The target must not contain any special characters")
+ )
+ if storage_type == "dir" or storage_type == "netfs":
if not target:
- raise forms.ValidationError(_('No path has been entered'))
+ raise forms.ValidationError(_("No path has been entered"))
return target
def clean_source(self):
- storage_type = self.cleaned_data['stg_type']
- source = self.cleaned_data['source']
- have_symbol = re.match('^[a-zA-Z0-9\/]+$', source)
- if storage_type == 'logical' or storage_type == 'netfs':
+ storage_type = self.cleaned_data["stg_type"]
+ source = self.cleaned_data["source"]
+ have_symbol = re.match("^[a-zA-Z0-9\/]+$", source)
+ if storage_type == "logical" or storage_type == "netfs":
if not source:
- raise forms.ValidationError(_('No device or path has been entered'))
+ raise forms.ValidationError(_("No device or path has been entered"))
if not have_symbol:
- raise forms.ValidationError(_('The disk source must not contain any special characters'))
+ raise forms.ValidationError(
+ _("The disk source must not contain any special characters")
+ )
return source
class CreateVolumeForm(forms.Form):
name = forms.CharField(max_length=120)
- format = forms.ChoiceField(required=True, choices=(('qcow2', 'qcow2 (recommended)'), ('qcow', 'qcow'), ('raw', 'raw')))
+ format = forms.ChoiceField(
+ required=True,
+ choices=(("qcow2", "qcow2 (recommended)"), ("qcow", "qcow"), ("raw", "raw")),
+ )
size = forms.IntegerField()
meta_prealloc = forms.BooleanField(required=False)
def clean_name(self):
- name = self.cleaned_data['name']
- have_symbol = re.match('^[a-zA-Z0-9._-]+$', name)
+ name = self.cleaned_data["name"]
+ have_symbol = re.match("^[a-zA-Z0-9._-]+$", name)
if not have_symbol:
- raise forms.ValidationError(_('The image name must not contain any special characters'))
+ raise forms.ValidationError(
+ _("The image name must not contain any special characters")
+ )
return name
@@ -67,14 +86,21 @@ class CloneImage(forms.Form):
name = forms.CharField(max_length=120)
image = forms.CharField(max_length=120)
convert = forms.BooleanField(required=False)
- format = forms.ChoiceField(required=False, choices=(('qcow2', 'qcow2 (recommended)'), ('qcow', 'qcow'), ('raw', 'raw')))
+ format = forms.ChoiceField(
+ required=False,
+ choices=(("qcow2", "qcow2 (recommended)"), ("qcow", "qcow"), ("raw", "raw")),
+ )
meta_prealloc = forms.BooleanField(required=False)
def clean_name(self):
- name = self.cleaned_data['name']
- have_symbol = re.match('^[a-zA-Z0-9._-]+$', name)
+ name = self.cleaned_data["name"]
+ have_symbol = re.match("^[a-zA-Z0-9._-]+$", name)
if not have_symbol:
- raise forms.ValidationError(_('The image name must not contain any special characters'))
+ raise forms.ValidationError(
+ _("The image name must not contain any special characters")
+ )
elif len(name) > 120:
- raise forms.ValidationError(_('The image name must not exceed 120 characters'))
+ raise forms.ValidationError(
+ _("The image name must not exceed 120 characters")
+ )
return name
diff --git a/storages/models.py b/storages/models.py
index fdca3bf..bb65887 100644
--- a/storages/models.py
+++ b/storages/models.py
@@ -3,45 +3,55 @@ from django.utils.translation import gettext_lazy as _
# Create your models here.
class Storages(models.Model):
- name = models.CharField(_('name'), max_length=20, error_messages={'required': _('No pool name has been entered')})
- status = models.IntegerField(_('status'))
- type = models.CharField(_('type'), max_length=100)
- size = models.IntegerField(_('size'))
- volumes = models.IntegerField(_('volumes'))
+ name = models.CharField(
+ _("name"),
+ max_length=20,
+ error_messages={"required": _("No pool name has been entered")},
+ )
+ status = models.IntegerField(_("status"))
+ type = models.CharField(_("type"), max_length=100)
+ size = models.IntegerField(_("size"))
+ volumes = models.IntegerField(_("volumes"))
class Meta:
managed = False
def __str__(self):
- return f'{self.name}'
+ return f"{self.name}"
class Volume(models.Model):
- name = models.CharField(_('name'), max_length=128)
- type = models.CharField(_('format'), max_length=12, choices=(('qcow2', 'qcow2 (recommended)'), ('qcow', 'qcow'), ('raw', 'raw')))
- allocation = models.IntegerField(_('allocation'))
- size = models.IntegerField(_('size'))
+ name = models.CharField(_("name"), max_length=128)
+ type = models.CharField(
+ _("format"),
+ max_length=12,
+ choices=(("qcow2", "qcow2 (recommended)"), ("qcow", "qcow"), ("raw", "raw")),
+ )
+ allocation = models.IntegerField(_("allocation"))
+ size = models.IntegerField(_("size"))
class Meta:
managed = False
verbose_name_plural = "Volumes"
def __str__(self):
- return f'{self.name}'
+ return f"{self.name}"
class Storage(models.Model):
- state = models.IntegerField(_('state'))
- size = models.IntegerField(_('size'))
- free = models.IntegerField(_('free'))
- status = models.CharField(_('status'), max_length=128)
- path = models.CharField(_('path'), max_length=128)
- type = models.CharField(_('type'), max_length=128)
- autostart = models.BooleanField(_('autostart'))
- volumes = models.ForeignKey(Volume, related_name="storage_volumes", on_delete=models.DO_NOTHING)
+ state = models.IntegerField(_("state"))
+ size = models.IntegerField(_("size"))
+ free = models.IntegerField(_("free"))
+ status = models.CharField(_("status"), max_length=128)
+ path = models.CharField(_("path"), max_length=128)
+ type = models.CharField(_("type"), max_length=128)
+ autostart = models.BooleanField(_("autostart"))
+ volumes = models.ForeignKey(
+ Volume, related_name="storage_volumes", on_delete=models.DO_NOTHING
+ )
class Meta:
managed = False
def __str__(self):
- return f'{self.path}'
+ return f"{self.path}"
diff --git a/storages/views.py b/storages/views.py
index 3828c41..58fb7df 100644
--- a/storages/views.py
+++ b/storages/views.py
@@ -27,7 +27,12 @@ def storages(request, compute_id):
errors = False
try:
- conn = wvmStorages(compute.hostname, compute.login, compute.password, compute.type)
+ conn = wvmStorages(
+ compute.hostname,
+ compute.login,
+ compute.password,
+ compute.type
+ )
storages = conn.get_storages_info()
secrets = conn.get_secrets()
@@ -45,7 +50,11 @@ def storages(request, compute_id):
msg = _("You need create secret for pool")
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")
messages.error(request, msg)
errors = True
@@ -69,8 +78,15 @@ def storages(request, compute_id):
data["target"],
)
else:
- conn.create_storage(data["stg_type"], data["name"], data["source"], data["target"])
- return HttpResponseRedirect(reverse("storage", args=[compute_id, data["name"]]))
+ conn.create_storage(
+ data["stg_type"],
+ data["name"],
+ data["source"],
+ data["target"],
+ )
+ return HttpResponseRedirect(
+ reverse("storage", args=[compute_id, data["name"]])
+ )
else:
for msg_err in form.errors.values():
messages.error(request, msg_err.as_text())
@@ -94,19 +110,26 @@ def storage(request, compute_id, pool):
target = os.path.normpath(os.path.join(path, str(f_name)))
if not target.startswith(path):
raise Exception(_("Security Issues with file uploading"))
-
+
try:
with open(target, "wb+") as f:
for chunk in f_name.chunks():
f.write(chunk)
except FileNotFoundError:
- messages.error(request, _("File not found. Check the path variable and filename"))
+ messages.error(
+ request, _("File not found. Check the path variable and filename")
+ )
compute = get_object_or_404(Compute, pk=compute_id)
meta_prealloc = False
form = CreateVolumeForm()
- conn = wvmStorage(compute.hostname, compute.login, compute.password, compute.type, pool)
+ conn = wvmStorage(
+ compute.hostname,
+ compute.login,
+ compute.password,
+ compute.type, pool
+ )
storages = conn.get_storages()
state = conn.is_active()
@@ -147,7 +170,9 @@ def storage(request, compute_id, pool):
volname = request.POST.get("volname", "")
vol = conn.get_volume(volname)
vol.delete(0)
- messages.success(request, _("Volume: %(vol)s is deleted.") % {"vol": volname})
+ messages.success(
+ request, _("Volume: %(vol)s is deleted.") % {"vol": volname}
+ )
return redirect(reverse("storage", args=[compute.id, pool]))
# return HttpResponseRedirect(request.get_full_path())
if "iso_upload" in request.POST:
@@ -156,7 +181,10 @@ def storage(request, compute_id, pool):
messages.error(request, error_msg)
else:
handle_uploaded_file(path, request.FILES["file"])
- messages.success(request, _("ISO: %(file)s is uploaded.") % {"file": request.FILES["file"]})
+ messages.success(
+ request,
+ _("ISO: %(file)s is uploaded.") % {"file": request.FILES["file"]},
+ )
return HttpResponseRedirect(request.get_full_path())
if "cln_volume" in request.POST:
form = CloneImage(request.POST)
@@ -174,10 +202,13 @@ def storage(request, compute_id, pool):
else:
format = None
try:
- name = conn.clone_volume(data["image"], data["name"], format, meta_prealloc)
+ name = conn.clone_volume(
+ data["image"], data["name"], format, meta_prealloc
+ )
messages.success(
request,
- _("%(image)s image cloned as %(name)s successfully") % {"image": data["image"], "name": name},
+ _("%(image)s image cloned as %(name)s successfully")
+ % {"image": data["image"], "name": name},
)
return HttpResponseRedirect(request.get_full_path())
except libvirtError as lib_err:
@@ -202,7 +233,13 @@ def create_volume(request, compute_id, pool):
compute = get_object_or_404(Compute, pk=compute_id)
meta_prealloc = False
- conn = wvmStorage(compute.hostname, compute.login, compute.password, compute.type, pool)
+ conn = wvmStorage(
+ compute.hostname,
+ compute.login,
+ compute.password,
+ compute.type,
+ pool
+ )
storages = conn.get_storages()
@@ -223,7 +260,9 @@ def create_volume(request, compute_id, pool):
disk_owner_uid,
disk_owner_gid,
)
- messages.success(request, _("Image file %(name)s is created successfully") % {"name": name})
+ messages.success(
+ request, _("Image file %(name)s is created successfully") % {"name": name}
+ )
else:
for msg_err in form.errors.values():
messages.error(request, msg_err.as_text())
@@ -241,7 +280,13 @@ def get_volumes(request, compute_id, pool):
data = {}
compute = get_object_or_404(Compute, pk=compute_id)
try:
- conn = wvmStorage(compute.hostname, compute.login, compute.password, compute.type, pool)
+ conn = wvmStorage(
+ compute.hostname,
+ compute.login,
+ compute.password,
+ compute.type,
+ pool
+ )
conn.refresh()
data["vols"] = sorted(conn.get_volumes())
except libvirtError:
diff --git a/virtsecrets/forms.py b/virtsecrets/forms.py
index 7ae478e..232973a 100644
--- a/virtsecrets/forms.py
+++ b/virtsecrets/forms.py
@@ -2,7 +2,10 @@ from django import forms
class AddSecret(forms.Form):
- ephemeral = forms.ChoiceField(required=True, choices=(('no', 'no'), ('yes', 'yes')))
- private = forms.ChoiceField(required=True, choices=(('no', 'no'), ('yes', 'yes')))
- usage_type = forms.ChoiceField(required=True, choices=(('ceph', 'ceph'), ('volume', 'volume'), ('iscsi', 'iscsi')))
+ ephemeral = forms.ChoiceField(required=True, choices=(("no", "no"), ("yes", "yes")))
+ private = forms.ChoiceField(required=True, choices=(("no", "no"), ("yes", "yes")))
+ usage_type = forms.ChoiceField(
+ required=True,
+ choices=(("ceph", "ceph"), ("volume", "volume"), ("iscsi", "iscsi")),
+ )
data = forms.CharField(max_length=100, required=True)
diff --git a/virtsecrets/views.py b/virtsecrets/views.py
index d7804c6..adf577f 100644
--- a/virtsecrets/views.py
+++ b/virtsecrets/views.py
@@ -35,7 +35,12 @@ def secrets(request, compute_id):
}
try:
- conn = wvmSecrets(compute.hostname, compute.login, compute.password, compute.type)
+ conn = wvmSecrets(
+ compute.hostname,
+ compute.login,
+ compute.password,
+ compute.type
+ )
secrets = conn.get_secrets()
for uuid in secrets:
diff --git a/vrtManager/hostdetails.py b/vrtManager/hostdetails.py
index 6ee97fb..0b7c313 100644
--- a/vrtManager/hostdetails.py
+++ b/vrtManager/hostdetails.py
@@ -42,8 +42,7 @@ class wvmHostDetails(wvmConnect):
total = sum(self.wvm.getCPUStats(-1, 0).values())
diff_idle = idle - prev_idle
diff_total = total - prev_total
- diff_usage = (1000 * (diff_total - diff_idle) /
- diff_total + 5) / 10
+ diff_usage = (1000 * (diff_total - diff_idle) / diff_total + 5) / 10
prev_total = total
prev_idle = idle
if num == 0:
@@ -61,6 +60,8 @@ class wvmHostDetails(wvmConnect):
info.append(self.wvm.getInfo()[0]) # architecture
info.append(self.wvm.getInfo()[1] * 1048576) # memory
info.append(self.wvm.getInfo()[2]) # cpu core count
- info.append(get_xml_path(self.wvm.getSysinfo(0), func=cpu_version)) # cpu version
+ info.append(
+ get_xml_path(self.wvm.getSysinfo(0), func=cpu_version)
+ ) # cpu version
info.append(self.wvm.getURI()) # uri
return info
diff --git a/vrtManager/instance.py b/vrtManager/instance.py
index 0931a98..0ae7435 100644
--- a/vrtManager/instance.py
+++ b/vrtManager/instance.py
@@ -21,10 +21,7 @@ try:
VIR_MIGRATE_POSTCOPY,
)
from libvirt import VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT
- from libvirt_qemu import (
- qemuAgentCommand,
- VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT
- )
+ from libvirt_qemu import qemuAgentCommand, VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT
except:
from libvirt import libvirtError, VIR_DOMAIN_XML_SECURE, VIR_MIGRATE_LIVE
@@ -94,7 +91,18 @@ class wvmInstances(wvmConnect):
dom = self.get_instance(name)
dom.resume()
- def moveto(self, conn, name, live, unsafe, undefine, offline, autoconverge=False, compress=False, postcopy=False):
+ def moveto(
+ self,
+ conn,
+ name,
+ live,
+ unsafe,
+ undefine,
+ offline,
+ autoconverge=False,
+ compress=False,
+ postcopy=False,
+ ):
flags = VIR_MIGRATE_PERSIST_DEST
if live and conn.get_status() != 5:
flags |= VIR_MIGRATE_LIVE
@@ -117,29 +125,39 @@ class wvmInstances(wvmConnect):
dom_emulator = conn.get_dom_emulator()
if dom_emulator != self.get_emulator(dom_arch):
- raise libvirtError("Destination host emulator is different. Cannot be migrated")
+ raise libvirtError(
+ "Destination host emulator is different. Cannot be migrated"
+ )
dom.migrate(self.wvm, flags, None, None, 0)
def graphics_type(self, name):
inst = self.get_instance(name)
- console_type = util.get_xml_path(inst.XMLDesc(0), "/domain/devices/graphics/@type")
+ console_type = util.get_xml_path(
+ inst.XMLDesc(0), "/domain/devices/graphics/@type"
+ )
if console_type is None:
return "None"
return console_type
def graphics_listen(self, name):
inst = self.get_instance(name)
- listener_addr = util.get_xml_path(inst.XMLDesc(0), "/domain/devices/graphics/@listen")
+ listener_addr = util.get_xml_path(
+ inst.XMLDesc(0), "/domain/devices/graphics/@listen"
+ )
if listener_addr is None:
- listener_addr = util.get_xml_path(inst.XMLDesc(0), "/domain/devices/graphics/listen/@address")
+ listener_addr = util.get_xml_path(
+ inst.XMLDesc(0), "/domain/devices/graphics/listen/@address"
+ )
if listener_addr is None:
return "None"
return listener_addr
def graphics_port(self, name):
inst = self.get_instance(name)
- console_port = util.get_xml_path(inst.XMLDesc(0), "/domain/devices/graphics/@port")
+ console_port = util.get_xml_path(
+ inst.XMLDesc(0), "/domain/devices/graphics/@port"
+ )
if console_port is None:
return "None"
return console_port
@@ -153,7 +171,9 @@ class wvmInstances(wvmConnect):
def graphics_passwd(self, name):
inst = self.get_instance(name)
- password = util.get_xml_path(inst.XMLDesc(VIR_DOMAIN_XML_SECURE), "/domain/devices/graphics/@passwd")
+ password = util.get_xml_path(
+ inst.XMLDesc(VIR_DOMAIN_XML_SECURE), "/domain/devices/graphics/@passwd"
+ )
if password is None:
return "None"
return password
@@ -167,27 +187,30 @@ class wvmInstance(wvmConnect):
def osinfo(self):
info_results = qemuAgentCommand(
- self.instance,
- '{"execute":"guest-get-osinfo"}',
- VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT, 0
- )
+ self.instance,
+ '{"execute":"guest-get-osinfo"}',
+ VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT,
+ 0,
+ )
timezone_results = qemuAgentCommand(
- self.instance,
- '{"execute":"guest-get-timezone"}',
- VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT, 0
- )
+ self.instance,
+ '{"execute":"guest-get-timezone"}',
+ VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT,
+ 0,
+ )
hostname_results = qemuAgentCommand(
- self.instance,
- '{"execute":"guest-get-host-name"}',
- VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT, 0
- )
+ self.instance,
+ '{"execute":"guest-get-host-name"}',
+ VIR_DOMAIN_QEMU_AGENT_COMMAND_DEFAULT,
+ 0,
+ )
- info_results = json.loads(info_results).get('return')
+ info_results = json.loads(info_results).get("return")
- timezone_results = json.loads(timezone_results).get('return')
- hostname_results = json.loads(hostname_results).get('return')
+ timezone_results = json.loads(timezone_results).get("return")
+ hostname_results = json.loads(hostname_results).get("return")
info_results.update(timezone_results)
info_results.update(hostname_results)
@@ -283,7 +306,11 @@ class wvmInstance(wvmConnect):
enabled = vcpu.get("enabled")
hotplug = vcpu.get("hotpluggable")
order = vcpu.get("order")
- vcpus[vcpu_id] = {"enabled": enabled, "hotpluggable": hotplug, "order": order}
+ vcpus[vcpu_id] = {
+ "enabled": enabled,
+ "hotpluggable": hotplug,
+ "order": order,
+ }
return vcpus
@@ -382,7 +409,9 @@ class wvmInstance(wvmConnect):
return
if self.is_agent_ready():
- self._ip_cache["qemuga"] = self._get_interface_addresses(VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT)
+ self._ip_cache["qemuga"] = self._get_interface_addresses(
+ VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT
+ )
arp_flag = 3 # libvirt."VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_ARP"
self._ip_cache["arp"] = self._get_interface_addresses(arp_flag)
@@ -395,9 +424,17 @@ class wvmInstance(wvmConnect):
interface_type = net.xpath("@type")[0]
mac_inst = net.xpath("mac/@address")[0]
nic_inst = net.xpath("source/@network|source/@bridge|source/@dev")[0]
- target_inst = "" if not net.xpath("target/@dev") else net.xpath("target/@dev")[0]
- link_state = "up" if not net.xpath("link") else net.xpath("link/@state")[0]
- filterref_inst = "" if not net.xpath("filterref/@filter") else net.xpath("filterref/@filter")[0]
+ target_inst = (
+ "" if not net.xpath("target/@dev") else net.xpath("target/@dev")[0]
+ )
+ link_state = (
+ "up" if not net.xpath("link") else net.xpath("link/@state")[0]
+ )
+ filterref_inst = (
+ ""
+ if not net.xpath("filterref/@filter")
+ else net.xpath("filterref/@filter")[0]
+ )
model_type = net.xpath("model/@type")[0]
if net.xpath("bandwidth/inbound"):
in_attr = net.xpath("bandwidth/inbound")[0]
@@ -451,7 +488,9 @@ class wvmInstance(wvmConnect):
dev = disk.xpath("target/@dev")[0]
bus = disk.xpath("target/@bus")[0]
try:
- src_file = disk.xpath("source/@file|source/@dev|source/@name")[0]
+ src_file = disk.xpath(
+ "source/@file|source/@dev|source/@name"
+ )[0]
except Exception:
v = disk.xpath("source/@volume")[0]
s_name = disk.xpath("source/@pool")[0]
@@ -480,7 +519,11 @@ class wvmInstance(wvmConnect):
readonly = True if disk.xpath("readonly") else False
shareable = True if disk.xpath("shareable") else False
- serial = disk.xpath("serial")[0].text if disk.xpath("serial") else None
+ serial = (
+ disk.xpath("serial")[0].text
+ if disk.xpath("serial")
+ else None
+ )
try:
vol = self.get_volume_by_path(src_file)
@@ -541,7 +584,15 @@ class wvmInstance(wvmConnect):
except:
pass
finally:
- result.append({"dev": dev, "image": volume, "storage": storage, "path": src_file, "bus": bus})
+ result.append(
+ {
+ "dev": dev,
+ "image": volume,
+ "storage": storage,
+ "path": src_file,
+ "bus": bus,
+ }
+ )
return result
return util.get_xml_path(self._XMLDesc(0), func=disks)
@@ -567,7 +618,9 @@ class wvmInstance(wvmConnect):
elif flag == -1: # Remove
os.remove(menu)
else:
- raise Exception("Unknown boot menu option, please choose one of 0:disable, 1:enable, -1:remove")
+ raise Exception(
+ "Unknown boot menu option, please choose one of 0:disable, 1:enable, -1:remove"
+ )
xmldom = ElementTree.tostring(tree).decode()
self._defineXML(xmldom)
@@ -614,7 +667,11 @@ class wvmInstance(wvmConnect):
elif dev_type == "usb":
pass
- boot_order[int(idx) - 1] = {"type": dev_type, "dev": dev_device, "target": dev_target}
+ boot_order[int(idx) - 1] = {
+ "type": dev_type,
+ "dev": dev_device,
+ "target": dev_target,
+ }
return boot_order
@@ -716,7 +773,7 @@ class wvmInstance(wvmConnect):
self,
target_dev,
source,
- source_info = None,
+ source_info=None,
pool_type="dir",
target_bus="ide",
disk_type="file",
@@ -733,7 +790,11 @@ class wvmInstance(wvmConnect):
):
additionals = ""
- if cache_mode is not None and cache_mode != "default" and disk_device != "cdrom":
+ if (
+ cache_mode is not None
+ and cache_mode != "default"
+ and disk_device != "cdrom"
+ ):
additionals += f"cache='{cache_mode}' "
if io_mode is not None and io_mode != "default":
additionals += f"io='{io_mode}' "
@@ -746,31 +807,33 @@ class wvmInstance(wvmConnect):
if disk_device == "cdrom":
xml_disk += f""
elif disk_device == "disk":
- xml_disk += f""
+ xml_disk += (
+ f""
+ )
- if disk_type == 'file':
+ if disk_type == "file":
xml_disk += f""
- elif disk_type == 'network':
- if pool_type == 'rbd':
- auth_type = source_info.get('auth_type')
- auth_user = source_info.get('auth_user')
+ elif disk_type == "network":
+ if pool_type == "rbd":
+ auth_type = source_info.get("auth_type")
+ auth_user = source_info.get("auth_user")
auth_uuid = source_info.get("auth_uuid")
xml_disk += f"""
"""
xml_disk += f""""""
for host in source_info.get("hosts"):
- if host.get('hostport'):
+ if host.get("hostport"):
xml_disk += f""""""
else:
xml_disk += f""""""
- xml_disk +=""""""
+ xml_disk += """"""
else:
raise Exception("Not implemented disk type")
else:
raise Exception("Not implemented disk type")
- xml_disk +=f""
+ xml_disk += f""
if readonly or disk_device == "cdrom":
xml_disk += """"""
if shareable:
@@ -787,7 +850,9 @@ class wvmInstance(wvmConnect):
def detach_disk(self, target_dev):
tree = etree.fromstring(self._XMLDesc(0))
- disk_el = tree.xpath("./devices/disk/target[@dev='{}']".format(target_dev))[0].getparent()
+ disk_el = tree.xpath("./devices/disk/target[@dev='{}']".format(target_dev))[
+ 0
+ ].getparent()
xml_disk = etree.tostring(disk_el).decode()
devices = tree.find("devices")
devices.remove(disk_el)
@@ -813,7 +878,9 @@ class wvmInstance(wvmConnect):
detect_zeroes_mode,
):
tree = etree.fromstring(self._XMLDesc(0))
- disk_el = tree.xpath("./devices/disk/target[@dev='{}']".format(target_dev))[0].getparent()
+ disk_el = tree.xpath("./devices/disk/target[@dev='{}']".format(target_dev))[
+ 0
+ ].getparent()
old_disk_type = disk_el.get("type")
old_disk_device = disk_el.get("device")
old_driver_name = disk_el.xpath("driver/@name")[0]
@@ -833,7 +900,9 @@ class wvmInstance(wvmConnect):
if old_disk_device == "cdrom":
xml_disk += f""
elif old_disk_device == "disk":
- xml_disk += f""
+ xml_disk += (
+ f""
+ )
xml_disk += f"""
"""
@@ -855,7 +924,7 @@ class wvmInstance(wvmConnect):
time.sleep(1)
cpu_use_now = self.instance.info()[4]
diff_usage = cpu_use_now - cpu_use_ago
- cpu_usage["cpu"] = 100 * diff_usage / (1 * nbcore * 10 ** 9)
+ cpu_usage["cpu"] = 100 * diff_usage / (1 * nbcore * 10**9)
else:
cpu_usage["cpu"] = 0
return cpu_usage
@@ -864,7 +933,7 @@ class wvmInstance(wvmConnect):
self.instance.setVcpu(str(cpu_id), enabled)
def set_vcpu_hotplug(self, status, vcpus_hotplug=0):
- """ vcpus_hotplug = 0 make all vpus hotpluggable """
+ """vcpus_hotplug = 0 make all vpus hotpluggable"""
vcpus_hotplug = int(self.get_vcpu()) if vcpus_hotplug == 0 else vcpus_hotplug
if self.get_status() == 5: # shutoff
if status:
@@ -887,7 +956,9 @@ class wvmInstance(wvmConnect):
parent.remove(vcpu)
self._defineXML(etree.tostring(tree).decode())
else:
- raise libvirtError("Please shutdown the instance then try to enable vCPU hotplug")
+ raise libvirtError(
+ "Please shutdown the instance then try to enable vCPU hotplug"
+ )
def mem_usage(self):
mem_usage = {}
@@ -983,9 +1054,13 @@ class wvmInstance(wvmConnect):
return telnet_port
def get_console_listener_addr(self):
- listener_addr = util.get_xml_path(self._XMLDesc(0), "/domain/devices/graphics/@listen")
+ listener_addr = util.get_xml_path(
+ self._XMLDesc(0), "/domain/devices/graphics/@listen"
+ )
if listener_addr is None:
- listener_addr = util.get_xml_path(self._XMLDesc(0), "/domain/devices/graphics/listen/@address")
+ listener_addr = util.get_xml_path(
+ self._XMLDesc(0), "/domain/devices/graphics/listen/@address"
+ )
if listener_addr is None:
return "127.0.0.1"
return listener_addr
@@ -1021,9 +1096,13 @@ class wvmInstance(wvmConnect):
return socket
def get_console_type(self):
- console_type = util.get_xml_path(self._XMLDesc(0), "/domain/devices/graphics/@type")
+ console_type = util.get_xml_path(
+ self._XMLDesc(0), "/domain/devices/graphics/@type"
+ )
if console_type is None:
- console_type = util.get_xml_path(self._XMLDesc(0), "/domain/devices/console/@type")
+ console_type = util.get_xml_path(
+ self._XMLDesc(0), "/domain/devices/console/@type"
+ )
return console_type
def set_console_type(self, console_type):
@@ -1046,18 +1125,24 @@ class wvmInstance(wvmConnect):
def get_console_port(self, console_type=None):
if console_type is None:
console_type = self.get_console_type()
- port = util.get_xml_path(self._XMLDesc(0), "/domain/devices/graphics[@type='%s']/@port" % console_type)
+ port = util.get_xml_path(
+ self._XMLDesc(0),
+ "/domain/devices/graphics[@type='%s']/@port" % console_type,
+ )
return port
def get_console_websocket_port(self):
console_type = self.get_console_type()
websocket_port = util.get_xml_path(
- self._XMLDesc(0), "/domain/devices/graphics[@type='%s']/@websocket" % console_type
+ self._XMLDesc(0),
+ "/domain/devices/graphics[@type='%s']/@websocket" % console_type,
)
return websocket_port
def get_console_passwd(self):
- return util.get_xml_path(self._XMLDesc(VIR_DOMAIN_XML_SECURE), "/domain/devices/graphics/@passwd")
+ return util.get_xml_path(
+ self._XMLDesc(VIR_DOMAIN_XML_SECURE), "/domain/devices/graphics/@passwd"
+ )
def set_console_passwd(self, passwd):
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
@@ -1100,10 +1185,15 @@ class wvmInstance(wvmConnect):
self._defineXML(newxml)
def get_console_keymap(self):
- return util.get_xml_path(self._XMLDesc(VIR_DOMAIN_XML_SECURE), "/domain/devices/graphics/@keymap") or ""
+ return (
+ util.get_xml_path(
+ self._XMLDesc(VIR_DOMAIN_XML_SECURE), "/domain/devices/graphics/@keymap"
+ )
+ or ""
+ )
def get_video_model(self):
- """ :return only primary video card"""
+ """:return only primary video card"""
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
tree = etree.fromstring(xml)
video_models = tree.xpath("/domain/devices/video/model")
@@ -1112,7 +1202,7 @@ class wvmInstance(wvmConnect):
return model.get("type")
def set_video_model(self, model):
- """ Changes only primary video card"""
+ """Changes only primary video card"""
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
tree = etree.fromstring(xml)
video_models = tree.xpath("/domain/devices/video/model")
@@ -1208,7 +1298,7 @@ class wvmInstance(wvmConnect):
self.instance.snapshotCreateXML(xml, flag)
def create_snapshot(self, name, desc=None):
- state = 'shutoff' if self.get_status()==5 else 'running'
+ state = "shutoff" if self.get_status() == 5 else "running"
xml = """
%s
%s
@@ -1227,11 +1317,17 @@ class wvmInstance(wvmConnect):
self.recover_snapshot_xml()
def change_snapshot_xml(self):
- xml_temp = self._XMLDesc(VIR_DOMAIN_XML_SECURE).replace("","")
+ xml_temp = self._XMLDesc(VIR_DOMAIN_XML_SECURE).replace(
+ "",
+ "",
+ )
self._defineXML(xml_temp)
def recover_snapshot_xml(self):
- xml_temp = self._XMLDesc(VIR_DOMAIN_XML_SECURE).replace("","")
+ xml_temp = self._XMLDesc(VIR_DOMAIN_XML_SECURE).replace(
+ "",
+ "",
+ )
self._defineXML(xml_temp)
def get_snapshot(self):
@@ -1239,8 +1335,12 @@ class wvmInstance(wvmConnect):
snapshot_list = self.instance.snapshotListNames(0)
for snapshot in snapshot_list:
snap = self.instance.snapshotLookupByName(snapshot, 0)
- snap_description = util.get_xml_path(snap.getXMLDesc(0), "/domainsnapshot/description")
- snap_time_create = util.get_xml_path(snap.getXMLDesc(0), "/domainsnapshot/creationTime")
+ snap_description = util.get_xml_path(
+ snap.getXMLDesc(0), "/domainsnapshot/description"
+ )
+ snap_time_create = util.get_xml_path(
+ snap.getXMLDesc(0), "/domainsnapshot/creationTime"
+ )
snapshots.append(
{
"date": datetime.fromtimestamp(int(snap_time_create)),
@@ -1338,7 +1438,9 @@ class wvmInstance(wvmConnect):
elm.set("file", clone_path)
vol = self.get_volume_by_path(source_file)
- vol_format = util.get_xml_path(vol.XMLDesc(0), "/volume/target/format/@type")
+ vol_format = util.get_xml_path(
+ vol.XMLDesc(0), "/volume/target/format/@type"
+ )
if vol_format == "qcow2" and meta_prealloc:
meta_prealloc = True
@@ -1373,7 +1475,9 @@ class wvmInstance(wvmConnect):
elm.set("name", clone_name)
vol = self.get_volume_by_path(source_name)
- vol_format = util.get_xml_path(vol.XMLDesc(0), "/volume/target/format/@type")
+ vol_format = util.get_xml_path(
+ vol.XMLDesc(0), "/volume/target/format/@type"
+ )
vol_clone_xml = f"""
@@ -1417,15 +1521,22 @@ class wvmInstance(wvmConnect):
bridge_name = None
return bridge_name
- def add_network(self, mac_address, source, source_type="net", model="virtio", nwfilter=None):
-
+ def add_network(
+ self,
+ mac_address,
+ source,
+ source_type="net",
+ model="virtio",
+ nwfilter=None
+ ):
+
if source_type == "net":
interface_type = "network"
elif source_type == "bridge":
interface_type = "bridge"
else:
interface_type = "direct"
-
+
# network modes not handled: default is bridge
xml_iface = f"""
@@ -1471,12 +1582,18 @@ class wvmInstance(wvmConnect):
net_source_type = network_data.get("net-source-0-type")
net_filter = network_data.get("net-nwfilter-0")
net_model = network_data.get("net-model-0")
-
+
# Remove interface first, but keep network interface XML definition
# If there is an error happened while adding changed one, then add removed one to back.
status = self.delete_network(net_mac)
try:
- self.add_network(net_mac, net_source, net_source_type, net_model, net_filter)
+ self.add_network(
+ net_mac,
+ net_source,
+ net_source_type,
+ net_model,
+ net_filter
+ )
except libvirtError:
if status is not None:
if self.get_status() == 1:
@@ -1485,12 +1602,11 @@ class wvmInstance(wvmConnect):
if self.get_status() == 5:
self.instance.attachDeviceFlags(status, VIR_DOMAIN_AFFECT_CONFIG)
-
def change_network_oldway(self, network_data):
- '''
- change network firsh version...
- will be removed if new one works as expected for all scenarios
- '''
+ """
+ change network firsh version...
+ will be removed if new one works as expected for all scenarios
+ """
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
tree = ElementTree.fromstring(xml)
for num, interface in enumerate(tree.findall("devices/interface")):
@@ -1512,9 +1628,13 @@ class wvmInstance(wvmConnect):
elif net_source_type == "iface":
source.set("dev", net_source)
else:
- raise libvirtError("Unknown network type: {}".format(net_source_type))
+ raise libvirtError(
+ "Unknown network type: {}".format(net_source_type)
+ )
else:
- raise libvirtError("Unknown network type: {}".format(interface.get("type")))
+ raise libvirtError(
+ "Unknown network type: {}".format(interface.get("type"))
+ )
source = interface.find("model")
if net_model != "default":
@@ -1615,7 +1735,12 @@ class wvmInstance(wvmConnect):
out_peak = out_qos.get("peak")
out_burst = out_qos.get("burst")
bound_list.append(
- {"direction": "outbound", "average": out_av, "peak": out_peak, "burst": out_burst}
+ {
+ "direction": "outbound",
+ "average": out_av,
+ "peak": out_peak,
+ "burst": out_burst,
+ }
)
qos_values[mac[0]] = bound_list
return qos_values
@@ -1652,9 +1777,13 @@ class wvmInstance(wvmConnect):
def unset_qos(self, mac, direction):
tree = etree.fromstring(self._XMLDesc(0))
- for direct in tree.xpath("/domain/devices/interface/bandwidth/{}".format(direction)):
+ for direct in tree.xpath(
+ "/domain/devices/interface/bandwidth/{}".format(direction)
+ ):
band_el = direct.getparent()
- interface_el = band_el.getparent() # parent bandwidth,its parent is interface
+ interface_el = (
+ band_el.getparent()
+ ) # parent bandwidth,its parent is interface
parent_mac = interface_el.xpath("mac/@address")
if parent_mac[0] == mac:
band_el.remove(direct)
@@ -1675,7 +1804,9 @@ class wvmInstance(wvmConnect):
def remove_guest_agent(self):
tree = etree.fromstring(self._XMLDesc(0))
- for target in tree.xpath("/domain/devices/channel[@type='unix']/target[@name='org.qemu.guest_agent.0']"):
+ for target in tree.xpath(
+ "/domain/devices/channel[@type='unix']/target[@name='org.qemu.guest_agent.0']"
+ ):
parent = target.getparent()
channel_xml = etree.tostring(parent).decode()
if self.get_status() == 1:
diff --git a/vrtManager/nwfilters.py b/vrtManager/nwfilters.py
index 8b8d1b9..7e8d535 100644
--- a/vrtManager/nwfilters.py
+++ b/vrtManager/nwfilters.py
@@ -88,7 +88,8 @@ class wvmNWFilter(wvmConnect):
tree = ElementTree.fromstring(self._XMLDesc(0))
rule_tree = tree.findall(
- "./rule[@action='%s'][@direction='%s'][@priority='%s']" % (action, direction, priority)
+ "./rule[@action='%s'][@direction='%s'][@priority='%s']"
+ % (action, direction, priority)
)
if rule_tree:
tree.remove(rule_tree[0])
@@ -111,7 +112,8 @@ class wvmNWFilter(wvmConnect):
rule_priority = rule.get("priority")
rule_directives = rule.find("./")
rule_tree = tree.findall(
- "./rule[@action='%s'][@direction='%s'][@priority='%s']" % (rule_action, rule_direction, rule_priority)
+ "./rule[@action='%s'][@direction='%s'][@priority='%s']"
+ % (rule_action, rule_direction, rule_priority)
)
if rule_tree:
diff --git a/vrtManager/storage.py b/vrtManager/storage.py
index 64f303d..b55aa5f 100644
--- a/vrtManager/storage.py
+++ b/vrtManager/storage.py
@@ -15,7 +15,13 @@ class wvmStorages(wvmConnect):
stg_vol = len(stg.listVolumes()) if stg_status else None
stg_size = stg.info()[1]
storages.append(
- {"name": pool, "status": stg_status, "type": stg_type, "volumes": stg_vol, "size": stg_size}
+ {
+ "name": pool,
+ "status": stg_status,
+ "type": stg_type,
+ "volumes": stg_vol,
+ "size": stg_size,
+ }
)
return storages
@@ -47,7 +53,9 @@ class wvmStorages(wvmConnect):
return stg
- def create_storage_ceph(self, stg_type, name, ceph_pool, ceph_host, ceph_user, secret):
+ def create_storage_ceph(
+ self, stg_type, name, ceph_pool, ceph_host, ceph_user, secret
+ ):
xml = f"""
{name}
@@ -65,7 +73,9 @@ class wvmStorages(wvmConnect):
stg.create(0)
stg.setAutostart(1)
- def create_storage_netfs(self, stg_type, name, netfs_host, source, source_format, target):
+ def create_storage_netfs(
+ self, stg_type, name, netfs_host, source, source_format, target
+ ):
xml = f"""
{name}
@@ -96,7 +106,12 @@ class wvmStorage(wvmConnect):
return self.pool.name()
def get_status(self):
- status = ["Not running", "Initializing pool, not available", "Running normally", "Running degraded"]
+ status = [
+ "Not running",
+ "Initializing pool, not available",
+ "Running normally",
+ "Running degraded",
+ ]
try:
return status[self.pool.info()[0]]
except ValueError:
@@ -161,27 +176,28 @@ class wvmStorage(wvmConnect):
hosts_array = []
for host in doc.xpath("/pool/source/host"):
- name = host.get('name')
+ name = host.get("name")
if name:
- port = host.get('port')
+ port = host.get("port")
if port:
hosts_array.append({"hostname": name, "hostport": port})
else:
hosts_array.append({"hostname": name})
- name = doc.get('name')
+ name = doc.get("name")
auth = doc.xpath("/pool/source/auth")
auth_type = auth[0].get("type")
auth_user = auth[0].get("username")
auth_uuid = auth[0].xpath("secret/@uuid")[0]
- return({
+ return {
"name": name,
"auth_type": auth_type,
"auth_user": auth_user,
"auth_uuid": auth_uuid,
- "hosts": hosts_array
- })
+ "hosts": hosts_array,
+ }
+
return util.get_xml_path(self._XMLDesc(0), func=hosts)
def get_pretty_allocation(self):
@@ -231,30 +247,49 @@ class wvmStorage(wvmConnect):
self.refresh()
vols = self.get_volumes()
- return [{"name": volname,
- "size": self.get_volume_size(volname),
- "allocation": self.get_volume_allocation(volname),
- "type": self.get_volume_format_type(volname)} for volname in vols]
-
- def get_volume_details(self, volname):
- with contextlib.suppress(Exception):
- self.refresh()
- return {
+ return [
+ {
"name": volname,
"size": self.get_volume_size(volname),
"allocation": self.get_volume_allocation(volname),
"type": self.get_volume_format_type(volname),
+ }
+ for volname in vols
+ ]
+
+ def get_volume_details(self, volname):
+ with contextlib.suppress(Exception):
+ self.refresh()
+ return {
+ "name": volname,
+ "size": self.get_volume_size(volname),
+ "allocation": self.get_volume_allocation(volname),
+ "type": self.get_volume_format_type(volname),
}
def update_volumes(self):
with contextlib.suppress(Exception):
self.refresh()
vols = self.get_volumes()
- return [{"name": volname, "size": self.get_volume_size(volname),
- "allocation": self.get_volume_allocation(volname),
- "type": self.get_volume_format_type(volname)} for volname in vols]
+ return [
+ {
+ "name": volname,
+ "size": self.get_volume_size(volname),
+ "allocation": self.get_volume_allocation(volname),
+ "type": self.get_volume_format_type(volname),
+ }
+ for volname in vols
+ ]
- def create_volume(self, name, size, vol_fmt="qcow2", metadata=False, disk_owner_uid=0, disk_owner_gid=0):
+ def create_volume(
+ self,
+ name,
+ size,
+ vol_fmt="qcow2",
+ metadata=False,
+ disk_owner_uid=0,
+ disk_owner_gid=0,
+ ):
size = int(size) * 1073741824
storage_type = self.get_type()
alloc = size
diff --git a/webvirtcloud/settings.py.template b/webvirtcloud/settings.py.template
index c35e24a..4d45be1 100644
--- a/webvirtcloud/settings.py.template
+++ b/webvirtcloud/settings.py.template
@@ -273,6 +273,14 @@ OTP_ENABLED = False
LOGIN_REQUIRED_IGNORE_VIEW_NAMES = ["accounts:login", "accounts:email_otp"]
+# EMAIL Config
+EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
+EMAIL_HOST = 'smtp.gmail.com'
+EMAIL_USE_TLS = True
+EMAIL_PORT = 587
+EMAIL_HOST_USER = #sender's email-id
+EMAIL_HOST_PASSWORD = #password associated with above email-id
+
# LDAP Config
#