From 2ec0d7b9f5c1354977b821c6b06c24a3ffa13142 Mon Sep 17 00:00:00 2001 From: Gergely Csatari Date: Thu, 26 Oct 2023 10:33:28 +0300 Subject: Removing project content and adding a note that the development continues in GitHub Change-Id: I25c58a679dbf92b2367d826429b7cda936bf9f0e Signed-off-by: Gergely Csatari --- src/booking/__init__.py | 8 - src/booking/admin.py | 16 - src/booking/apps.py | 15 - src/booking/forms.py | 123 -------- src/booking/lib.py | 36 --- src/booking/migrations/0001_initial.py | 68 ---- src/booking/migrations/0002_booking_pdf.py | 18 -- src/booking/migrations/0003_auto_20190115_1733.py | 30 -- src/booking/migrations/0004_auto_20190124_1700.py | 20 -- src/booking/migrations/0005_booking_idf.py | 18 -- .../migrations/0006_booking_opnfv_config.py | 20 -- .../0007_remove_booking_config_bundle.py | 17 - src/booking/migrations/0008_auto_20201109_1947.py | 30 -- src/booking/migrations/0009_booking_complete.py | 18 -- src/booking/migrations/__init__.py | 0 src/booking/models.py | 72 ----- src/booking/quick_deployer.py | 343 --------------------- src/booking/stats.py | 109 ------- src/booking/tests/__init__.py | 8 - src/booking/tests/test_models.py | 210 ------------- src/booking/tests/test_quick_booking.py | 180 ----------- src/booking/tests/test_stats.py | 59 ---- src/booking/urls.py | 53 ---- src/booking/views.py | 211 ------------- 24 files changed, 1682 deletions(-) delete mode 100644 src/booking/__init__.py delete mode 100644 src/booking/admin.py delete mode 100644 src/booking/apps.py delete mode 100644 src/booking/forms.py delete mode 100644 src/booking/lib.py delete mode 100644 src/booking/migrations/0001_initial.py delete mode 100644 src/booking/migrations/0002_booking_pdf.py delete mode 100644 src/booking/migrations/0003_auto_20190115_1733.py delete mode 100644 src/booking/migrations/0004_auto_20190124_1700.py delete mode 100644 src/booking/migrations/0005_booking_idf.py delete mode 100644 src/booking/migrations/0006_booking_opnfv_config.py delete mode 100644 src/booking/migrations/0007_remove_booking_config_bundle.py delete mode 100644 src/booking/migrations/0008_auto_20201109_1947.py delete mode 100644 src/booking/migrations/0009_booking_complete.py delete mode 100644 src/booking/migrations/__init__.py delete mode 100644 src/booking/models.py delete mode 100644 src/booking/quick_deployer.py delete mode 100644 src/booking/stats.py delete mode 100644 src/booking/tests/__init__.py delete mode 100644 src/booking/tests/test_models.py delete mode 100644 src/booking/tests/test_quick_booking.py delete mode 100644 src/booking/tests/test_stats.py delete mode 100644 src/booking/urls.py delete mode 100644 src/booking/views.py (limited to 'src/booking') diff --git a/src/booking/__init__.py b/src/booking/__init__.py deleted file mode 100644 index b6fef6c..0000000 --- a/src/booking/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Max Breitenfeldt and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## diff --git a/src/booking/admin.py b/src/booking/admin.py deleted file mode 100644 index 162777e..0000000 --- a/src/booking/admin.py +++ /dev/null @@ -1,16 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Max Breitenfeldt and others. -# Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - - -from django.contrib import admin - -from booking.models import Booking - -admin.site.register(Booking) diff --git a/src/booking/apps.py b/src/booking/apps.py deleted file mode 100644 index 99bf115..0000000 --- a/src/booking/apps.py +++ /dev/null @@ -1,15 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Max Breitenfeldt and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - - -from django.apps import AppConfig - - -class BookingConfig(AppConfig): - name = 'booking' diff --git a/src/booking/forms.py b/src/booking/forms.py deleted file mode 100644 index 9c9b053..0000000 --- a/src/booking/forms.py +++ /dev/null @@ -1,123 +0,0 @@ -############################################################################## -# Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## -import django.forms as forms -from django.forms.widgets import NumberInput - -from workflow.forms import ( - MultipleSelectFilterField, - MultipleSelectFilterWidget) -from account.models import UserProfile -from resource_inventory.models import Image, Installer, Scenario -from workflow.forms import SearchableSelectMultipleField -from booking.lib import get_user_items, get_user_field_opts - - -class QuickBookingForm(forms.Form): - # Django Form class for Express Booking - purpose = forms.CharField(max_length=1000) - project = forms.CharField(max_length=400) - hostname = forms.CharField(required=False, max_length=400) - global_cloud_config = forms.CharField(widget=forms.Textarea, required=False) - - installer = forms.ModelChoiceField(queryset=Installer.objects.all(), required=False) - scenario = forms.ModelChoiceField(queryset=Scenario.objects.all(), required=False) - - def __init__(self, data=None, user=None, lab_data=None, *args, **kwargs): - if "default_user" in kwargs: - default_user = kwargs.pop("default_user") - else: - default_user = "you" - self.default_user = default_user - - super(QuickBookingForm, self).__init__(data=data, **kwargs) - - image_help_text = 'Image can be set only for single-node bookings. For multi-node bookings set image through Design a POD.' - self.fields["image"] = forms.ModelChoiceField( - Image.objects.filter(public=True) | Image.objects.filter(owner=user), required=False - ) - - self.fields['image'].widget.attrs.update({ - 'class': 'has-popover', - 'data-content': image_help_text, - 'data-placement': 'bottom', - 'data-container': 'body' - }) - - self.fields['users'] = SearchableSelectMultipleField( - queryset=UserProfile.objects.filter(public_user=True).select_related('user').exclude(user=user), - items=get_user_items(exclude=user), - required=False, - **get_user_field_opts() - ) - - self.fields['length'] = forms.IntegerField( - widget=NumberInput( - attrs={ - "type": "range", - 'min': "1", - "max": "21", - "value": "1" - } - ) - ) - - self.fields['filter_field'] = MultipleSelectFilterField(widget=MultipleSelectFilterWidget(**lab_data)) - - hostname_help_text = 'Hostname can be set only for single-node bookings. For multi-node bookings set hostname through Design a POD.' - self.fields['hostname'].widget.attrs.update({ - 'class': 'has-popover', - 'data-content': hostname_help_text, - 'data-placement': 'top', - 'data-container': 'body' - }) - - def build_user_list(self): - """ - Build list of UserProfiles. - - returns a mapping of UserProfile ids to displayable objects expected by - searchable multiple select widget - """ - try: - users = {} - d_qset = UserProfile.objects.select_related('user').all().exclude(user__username=self.default_user) - for userprofile in d_qset: - user = { - 'id': userprofile.user.id, - 'expanded_name': userprofile.full_name, - 'small_name': userprofile.user.username, - 'string': userprofile.email_addr - } - - users[userprofile.user.id] = user - - return users - except Exception: - pass - - def build_search_widget_attrs(self, chosen_users, default_user="you"): - - attrs = { - 'set': self.build_user_list(), - 'show_from_noentry': "false", - 'show_x_results': 10, - 'scrollable': "false", - 'selectable_limit': -1, - 'name': "users", - 'placeholder': "username", - 'initial': chosen_users, - 'edit': False - } - return attrs - - -class HostReImageForm(forms.Form): - - image_id = forms.IntegerField() - host_id = forms.IntegerField() diff --git a/src/booking/lib.py b/src/booking/lib.py deleted file mode 100644 index 8c87979..0000000 --- a/src/booking/lib.py +++ /dev/null @@ -1,36 +0,0 @@ -############################################################################## -# Copyright (c) 2019 Parker Berberian, Sawyer Bergeron, and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - -from account.models import UserProfile - - -def get_user_field_opts(): - return { - 'show_from_noentry': False, - 'show_x_results': 5, - 'results_scrollable': True, - 'selectable_limit': -1, - 'placeholder': 'Search for other users', - 'name': 'users', - 'disabled': False - } - - -def get_user_items(exclude=None): - qs = UserProfile.objects.filter(public_user=True).select_related('user').exclude(user=exclude) - items = {} - for up in qs: - item = { - 'id': up.id, - 'expanded_name': up.full_name if up.full_name else up.user.username, - 'small_name': up.user.username, - 'string': up.email_addr if up.email_addr else up.user.username, - } - items[up.id] = item - return items diff --git a/src/booking/migrations/0001_initial.py b/src/booking/migrations/0001_initial.py deleted file mode 100644 index 20415fe..0000000 --- a/src/booking/migrations/0001_initial.py +++ /dev/null @@ -1,68 +0,0 @@ -# Generated by Django 2.1 on 2018-09-14 14:48 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('account', '0001_initial'), - ('resource_inventory', '__first__'), - ] - - operations = [ - migrations.CreateModel( - name='Booking', - fields=[ - ('id', models.AutoField(primary_key=True, serialize=False)), - ('start', models.DateTimeField()), - ('end', models.DateTimeField()), - ('reset', models.BooleanField(default=False)), - ('jira_issue_id', models.IntegerField(blank=True, null=True)), - ('jira_issue_status', models.CharField(blank=True, max_length=50)), - ('purpose', models.CharField(max_length=300)), - ('ext_count', models.IntegerField(default=2)), - ('project', models.CharField(blank=True, default='', max_length=100, null=True)), - ('collaborators', models.ManyToManyField(related_name='collaborators', to=settings.AUTH_USER_MODEL)), - ('config_bundle', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='resource_inventory.ConfigBundle')), - ('lab', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='account.Lab')), - ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='owner', to=settings.AUTH_USER_MODEL)), - ('resource', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='resource_inventory.ResourceBundle')), - ], - options={ - 'db_table': 'booking', - }, - ), - migrations.CreateModel( - name='Installer', - fields=[ - ('id', models.AutoField(primary_key=True, serialize=False)), - ('name', models.CharField(max_length=30)), - ], - ), - migrations.CreateModel( - name='Opsys', - fields=[ - ('id', models.AutoField(primary_key=True, serialize=False)), - ('name', models.CharField(max_length=100)), - ('sup_installers', models.ManyToManyField(blank=True, to='booking.Installer')), - ], - ), - migrations.CreateModel( - name='Scenario', - fields=[ - ('id', models.AutoField(primary_key=True, serialize=False)), - ('name', models.CharField(max_length=300)), - ], - ), - migrations.AddField( - model_name='installer', - name='sup_scenarios', - field=models.ManyToManyField(blank=True, to='booking.Scenario'), - ), - ] diff --git a/src/booking/migrations/0002_booking_pdf.py b/src/booking/migrations/0002_booking_pdf.py deleted file mode 100644 index 53232c9..0000000 --- a/src/booking/migrations/0002_booking_pdf.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.1 on 2018-11-09 16:09 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('booking', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='booking', - name='pdf', - field=models.TextField(blank=True, default=''), - ), - ] diff --git a/src/booking/migrations/0003_auto_20190115_1733.py b/src/booking/migrations/0003_auto_20190115_1733.py deleted file mode 100644 index 70eecfe..0000000 --- a/src/booking/migrations/0003_auto_20190115_1733.py +++ /dev/null @@ -1,30 +0,0 @@ -# Generated by Django 2.1 on 2019-01-15 17:33 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('booking', '0002_booking_pdf'), - ] - - operations = [ - migrations.RemoveField( - model_name='installer', - name='sup_scenarios', - ), - migrations.RemoveField( - model_name='opsys', - name='sup_installers', - ), - migrations.DeleteModel( - name='Installer', - ), - migrations.DeleteModel( - name='Opsys', - ), - migrations.DeleteModel( - name='Scenario', - ), - ] diff --git a/src/booking/migrations/0004_auto_20190124_1700.py b/src/booking/migrations/0004_auto_20190124_1700.py deleted file mode 100644 index baa32d2..0000000 --- a/src/booking/migrations/0004_auto_20190124_1700.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 2.1 on 2019-01-24 17:00 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('booking', '0003_auto_20190115_1733'), - ] - - operations = [ - migrations.AlterField( - model_name='booking', - name='owner', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='owner', to=settings.AUTH_USER_MODEL), - ), - ] diff --git a/src/booking/migrations/0005_booking_idf.py b/src/booking/migrations/0005_booking_idf.py deleted file mode 100644 index 31e9170..0000000 --- a/src/booking/migrations/0005_booking_idf.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.1 on 2019-04-12 19:27 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('booking', '0004_auto_20190124_1700'), - ] - - operations = [ - migrations.AddField( - model_name='booking', - name='idf', - field=models.TextField(blank=True, default=''), - ), - ] diff --git a/src/booking/migrations/0006_booking_opnfv_config.py b/src/booking/migrations/0006_booking_opnfv_config.py deleted file mode 100644 index e5ffc71..0000000 --- a/src/booking/migrations/0006_booking_opnfv_config.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 2.1 on 2019-05-01 18:02 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('resource_inventory', '0010_auto_20190430_1405'), - ('booking', '0005_booking_idf'), - ] - - operations = [ - migrations.AddField( - model_name='booking', - name='opnfv_config', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='resource_inventory.OPNFVConfig'), - ), - ] diff --git a/src/booking/migrations/0007_remove_booking_config_bundle.py b/src/booking/migrations/0007_remove_booking_config_bundle.py deleted file mode 100644 index dcd2e1c..0000000 --- a/src/booking/migrations/0007_remove_booking_config_bundle.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 2.2 on 2020-02-18 15:36 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('booking', '0006_booking_opnfv_config'), - ] - - operations = [ - migrations.RemoveField( - model_name='booking', - name='config_bundle', - ), - ] diff --git a/src/booking/migrations/0008_auto_20201109_1947.py b/src/booking/migrations/0008_auto_20201109_1947.py deleted file mode 100644 index 289e476..0000000 --- a/src/booking/migrations/0008_auto_20201109_1947.py +++ /dev/null @@ -1,30 +0,0 @@ -# Generated by Django 2.2 on 2020-11-09 19:47 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('booking', '0007_remove_booking_config_bundle'), - ] - - operations = [ - migrations.AlterField( - model_name='booking', - name='collaborators', - field=models.ManyToManyField(blank=True, related_name='collaborators', to=settings.AUTH_USER_MODEL), - ), - migrations.AlterField( - model_name='booking', - name='opnfv_config', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='resource_inventory.OPNFVConfig'), - ), - migrations.AlterField( - model_name='booking', - name='resource', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='resource_inventory.ResourceBundle'), - ), - ] diff --git a/src/booking/migrations/0009_booking_complete.py b/src/booking/migrations/0009_booking_complete.py deleted file mode 100644 index e291a83..0000000 --- a/src/booking/migrations/0009_booking_complete.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 2.2 on 2021-09-07 15:14 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('booking', '0008_auto_20201109_1947'), - ] - - operations = [ - migrations.AddField( - model_name='booking', - name='complete', - field=models.BooleanField(default=False), - ), - ] diff --git a/src/booking/migrations/__init__.py b/src/booking/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/booking/models.py b/src/booking/models.py deleted file mode 100644 index 966f1c2..0000000 --- a/src/booking/models.py +++ /dev/null @@ -1,72 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Max Breitenfeldt and others. -# Copyright (c) 2018 Sawyer Bergeron, Parker Berberian, and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - - -from resource_inventory.models import ResourceBundle, OPNFVConfig -from account.models import Lab -from django.contrib.auth.models import User -from django.db import models -import resource_inventory.resource_manager - - -class Booking(models.Model): - id = models.AutoField(primary_key=True) - # All bookings are owned by the user who requested it - owner = models.ForeignKey(User, on_delete=models.PROTECT, related_name='owner') - # an owner can add other users to the booking - collaborators = models.ManyToManyField(User, blank=True, related_name='collaborators') - # start and end time - start = models.DateTimeField() - end = models.DateTimeField() - reset = models.BooleanField(default=False) - jira_issue_id = models.IntegerField(null=True, blank=True) - jira_issue_status = models.CharField(max_length=50, blank=True) - purpose = models.CharField(max_length=300, blank=False) - # bookings can be extended a limited number of times - ext_count = models.IntegerField(default=2) - # the hardware that the user has booked - resource = models.ForeignKey(ResourceBundle, on_delete=models.SET_NULL, null=True, blank=True) - opnfv_config = models.ForeignKey(OPNFVConfig, on_delete=models.SET_NULL, null=True, blank=True) - project = models.CharField(max_length=100, default="", blank=True, null=True) - lab = models.ForeignKey(Lab, null=True, on_delete=models.SET_NULL) - pdf = models.TextField(blank=True, default="") - idf = models.TextField(blank=True, default="") - - complete = models.BooleanField(default=False) - - class Meta: - db_table = 'booking' - - def save(self, *args, **kwargs): - """ - Save the booking if self.user is authorized and there is no overlapping booking. - - Raise PermissionError if the user is not authorized - Raise ValueError if there is an overlapping booking - """ - if self.start >= self.end: - raise ValueError('Start date is after end date') - # conflicts end after booking starts, and start before booking ends - conflicting_dates = Booking.objects.filter(resource=self.resource).exclude(id=self.id) - conflicting_dates = conflicting_dates.filter(end__gt=self.start) - conflicting_dates = conflicting_dates.filter(start__lt=self.end) - if conflicting_dates.count() > 0: - raise ValueError('This booking overlaps with another booking') - return super(Booking, self).save(*args, **kwargs) - - def delete(self, *args, **kwargs): - res = self.resource - self.resource = None - self.save() - resource_inventory.resource_manager.ResourceManager.getInstance().deleteResourceBundle(res) - return super(self.__class__, self).delete(*args, **kwargs) - - def __str__(self): - return str(self.purpose) + ' from ' + str(self.start) + ' until ' + str(self.end) diff --git a/src/booking/quick_deployer.py b/src/booking/quick_deployer.py deleted file mode 100644 index 4b85d76..0000000 --- a/src/booking/quick_deployer.py +++ /dev/null @@ -1,343 +0,0 @@ -############################################################################## -# Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - - -import json -import yaml -from django.db.models import Q -from django.db import transaction -from datetime import timedelta -from django.utils import timezone -from django.core.exceptions import ValidationError -from account.models import Lab, UserProfile - -from resource_inventory.models import ( - ResourceTemplate, - Image, - OPNFVRole, - OPNFVConfig, - ResourceOPNFVConfig, - ResourceConfiguration, - NetworkConnection, - InterfaceConfiguration, - Network, - CloudInitFile, -) -from resource_inventory.resource_manager import ResourceManager -from resource_inventory.pdf_templater import PDFTemplater -from notifier.manager import NotificationHandler -from booking.models import Booking -from dashboard.exceptions import BookingLengthException -from api.models import JobFactory - - -def parse_resource_field(resource_json): - """ - Parse the json from the frontend. - - returns a reference to the selected Lab and ResourceTemplate objects - """ - lab, template = (None, None) - lab_dict = resource_json['lab'] - for lab_info in lab_dict.values(): - if lab_info['selected']: - lab = Lab.objects.get(lab_user__id=lab_info['id']) - - resource_dict = resource_json['resource'] - for resource_info in resource_dict.values(): - if resource_info['selected']: - template = ResourceTemplate.objects.get(pk=resource_info['id']) - - if lab is None: - raise ValidationError("No lab was selected") - if template is None: - raise ValidationError("No Host was selected") - - return lab, template - - -def update_template(old_template, image, hostname, user, global_cloud_config=None): - """ - Duplicate a template to the users account and update configured fields. - - The dashboard presents users with preconfigured resource templates, - but the user might want to make small modifications, e.g hostname and - linux distro. So we copy the public template and create a private version - to the user's profile, and mark it temporary. When the booking ends the - new template is deleted - """ - name = user.username + "'s Copy of '" + old_template.name + "'" - num_copies = ResourceTemplate.objects.filter(name__startswith=name).count() - template = ResourceTemplate.objects.create( - name=name if num_copies == 0 else name + " (" + str(num_copies) + ")", - xml=old_template.xml, - owner=user, - lab=old_template.lab, - description=old_template.description, - public=False, - temporary=True, - private_vlan_pool=old_template.private_vlan_pool, - public_vlan_pool=old_template.public_vlan_pool, - copy_of=old_template - ) - - for old_network in old_template.networks.all(): - Network.objects.create( - name=old_network.name, - bundle=template, - is_public=old_network.is_public - ) - # We are assuming there is only one opnfv config per public resource template - old_opnfv = template.opnfv_config.first() - if old_opnfv: - opnfv_config = OPNFVConfig.objects.create( - installer=old_opnfv.installer, - scenario=old_opnfv.installer, - template=template, - name=old_opnfv.installer, - ) - # I am explicitly leaving opnfv_config.networks empty to avoid - # problems with duplicated / shared networks. In the quick deploy, - # there is never multiple networks anyway. This may have to change in the future - - for old_config in old_template.getConfigs(): - image_to_set = image - if not image: - image_to_set = old_config.image - - config = ResourceConfiguration.objects.create( - profile=old_config.profile, - image=image_to_set, - template=template, - is_head_node=old_config.is_head_node, - name=hostname if len(old_template.getConfigs()) == 1 else old_config.name, - # cloud_init_files=old_config.cloud_init_files.set() - ) - - for file in old_config.cloud_init_files.all(): - config.cloud_init_files.add(file) - - if global_cloud_config: - config.cloud_init_files.add(global_cloud_config) - config.save() - - for old_iface_config in old_config.interface_configs.all(): - iface_config = InterfaceConfiguration.objects.create( - profile=old_iface_config.profile, - resource_config=config - ) - - for old_connection in old_iface_config.connections.all(): - iface_config.connections.add(NetworkConnection.objects.create( - network=template.networks.get(name=old_connection.network.name), - vlan_is_tagged=old_connection.vlan_is_tagged - )) - - for old_res_opnfv in old_config.resource_opnfv_config.all(): - if old_opnfv: - ResourceOPNFVConfig.objects.create( - role=old_opnfv.role, - resource_config=config, - opnfv_config=opnfv_config - ) - return template - - -def generate_opnfvconfig(scenario, installer, template): - return OPNFVConfig.objects.create( - scenario=scenario, - installer=installer, - template=template - ) - - -def generate_hostopnfv(hostconfig, opnfvconfig): - role = None - try: - role = OPNFVRole.objects.get(name="Jumphost") - except Exception: - role = OPNFVRole.objects.create( - name="Jumphost", - description="Single server jumphost role" - ) - return ResourceOPNFVConfig.objects.create( - role=role, - host_config=hostconfig, - opnfv_config=opnfvconfig - ) - - -def generate_resource_bundle(template): - resource_manager = ResourceManager.getInstance() - resource_bundle = resource_manager.instantiateTemplate(template) - return resource_bundle - - -def check_invariants(**kwargs): - # TODO: This should really happen in the BookingForm validation methods - image = kwargs['image'] - lab = kwargs['lab'] - length = kwargs['length'] - # check that image os is compatible with installer - if image: - if image.from_lab != lab: - raise ValidationError("The chosen image is not available at the chosen hosting lab") - # TODO - # if image.host_type != host_profile: - # raise ValidationError("The chosen image is not available for the chosen host type") - if not image.public and image.owner != kwargs['owner']: - raise ValidationError("You are not the owner of the chosen private image") - if length < 1 or length > 21: - raise BookingLengthException("Booking must be between 1 and 21 days long") - - -def create_from_form(form, request): - """ - Parse data from QuickBookingForm to create booking - """ - resource_field = form.cleaned_data['filter_field'] - # users_field = form.cleaned_data['users'] - hostname = 'opnfv_host' if not form.cleaned_data['hostname'] else form.cleaned_data['hostname'] - - global_cloud_config = None if not form.cleaned_data['global_cloud_config'] else form.cleaned_data['global_cloud_config'] - - if global_cloud_config: - form.cleaned_data['global_cloud_config'] = create_ci_file(global_cloud_config) - - # image = form.cleaned_data['image'] - # scenario = form.cleaned_data['scenario'] - # installer = form.cleaned_data['installer'] - - lab, resource_template = parse_resource_field(resource_field) - data = form.cleaned_data - data['hostname'] = hostname - data['lab'] = lab - data['resource_template'] = resource_template - data['owner'] = request.user - - return _create_booking(data) - - -def create_from_API(body, user): - """ - Parse data from Automation API to create booking - """ - booking_info = json.loads(body.decode('utf-8')) - - data = {} - data['purpose'] = booking_info['purpose'] - data['project'] = booking_info['project'] - data['users'] = [UserProfile.objects.get(user__username=username) - for username in booking_info['collaborators']] - data['hostname'] = booking_info['hostname'] - data['length'] = booking_info['length'] - data['installer'] = None - data['scenario'] = None - - data['image'] = Image.objects.get(pk=booking_info['imageLabID']) - - data['resource_template'] = ResourceTemplate.objects.get(pk=booking_info['templateID']) - data['lab'] = data['resource_template'].lab - data['owner'] = user - - if 'global_cloud_config' in data.keys(): - data['global_cloud_config'] = CloudInitFile.objects.get(id=data['global_cloud_config']) - - return _create_booking(data) - - -def create_ci_file(data: str) -> CloudInitFile: - try: - d = yaml.load(data) - if not (type(d) is dict): - raise Exception("CI file was valid yaml but was not a dict") - except Exception: - raise ValidationError("The provided Cloud Config is not valid yaml, please refer to the Cloud Init documentation for expected structure") - print("about to create global cloud config") - config = CloudInitFile.create(text=data, priority=CloudInitFile.objects.count()) - print("made global cloud config") - - return config - - -@transaction.atomic -def _create_booking(data): - check_invariants(**data) - - # check booking privileges - # TODO: use the canonical booking_allowed method because now template might have multiple - # machines - if Booking.objects.filter(owner=data['owner'], end__gt=timezone.now()).count() >= 3 and not data['owner'].userprofile.booking_privledge: - raise PermissionError("You do not have permission to have more than 3 bookings at a time.") - - ResourceManager.getInstance().templateIsReservable(data['resource_template']) - - resource_template = update_template(data['resource_template'], data['image'], data['hostname'], data['owner'], global_cloud_config=data['global_cloud_config']) - - # generate resource bundle - resource_bundle = generate_resource_bundle(resource_template) - - # generate booking - booking = Booking.objects.create( - purpose=data['purpose'], - project=data['project'], - lab=data['lab'], - owner=data['owner'], - start=timezone.now(), - end=timezone.now() + timedelta(days=int(data['length'])), - resource=resource_bundle, - opnfv_config=None - ) - - booking.pdf = PDFTemplater.makePDF(booking) - - for collaborator in data['users']: # list of Users (not UserProfile) - booking.collaborators.add(collaborator.user) - - booking.save() - - # generate job - JobFactory.makeCompleteJob(booking) - NotificationHandler.notify_new_booking(booking) - - return booking - - -def drop_filter(user): - """ - Return a dictionary that contains filters. - - Only certain installlers are supported on certain images, etc - so the image filter indexed at [imageid][installerid] is truthy if - that installer is supported on that image - """ - installer_filter = {} - scenario_filter = {} - - images = Image.objects.filter(Q(public=True) | Q(owner=user)) - image_filter = {} - for image in images: - image_filter[image.id] = { - 'lab': 'lab_' + str(image.from_lab.lab_user.id), - 'architecture': str(image.architecture), - 'name': image.name - } - - resource_filter = {} - templates = ResourceTemplate.objects.filter(Q(public=True) | Q(owner=user)) - for rt in templates: - profiles = [conf.profile for conf in rt.getConfigs()] - resource_filter["resource_" + str(rt.id)] = [str(p.architecture) for p in profiles] - - return { - 'installer_filter': json.dumps(installer_filter), - 'scenario_filter': json.dumps(scenario_filter), - 'image_filter': json.dumps(image_filter), - 'resource_profile_map': json.dumps(resource_filter), - } diff --git a/src/booking/stats.py b/src/booking/stats.py deleted file mode 100644 index 5a59d32..0000000 --- a/src/booking/stats.py +++ /dev/null @@ -1,109 +0,0 @@ -############################################################################## -# Copyright (c) 2020 Parker Berberian, Sawyer Bergeron, Sean Smith and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## -import os -from booking.models import Booking -from resource_inventory.models import ResourceQuery, ResourceProfile -from datetime import datetime, timedelta -from collections import Counter -import pytz - - -class StatisticsManager(object): - - @staticmethod - def getContinuousBookingTimeSeries(span=28): - """ - Calculate Booking usage data points. - - Gathers all active bookings that fall in interval [(now - span), (now + 1 week)]. - x data points are every 12 hours - y values are the integer number of bookings/users active at time - """ - - anuket_colors = [ - '#6BDAD5', # Turquoise - '#E36386', # Pale Violet Red - '#F5B335', # Sandy Brown - '#007473', # Teal - '#BCE194', # Gainsboro - '#00CE7C', # Sea Green - ] - - lfedge_colors = [ - '#0049B0', - '#B481A5', - '#6CAFE4', - '#D33668', - '#28245A' - ] - - x = [] - y = [] - users = [] - projects = [] - profiles = {str(profile): [] for profile in ResourceProfile.objects.all()} - - now = datetime.now(pytz.utc) - delta = timedelta(days=span) - start = now - delta - end = now + timedelta(weeks=1) - - bookings = Booking.objects.filter( - start__lte=end, - end__gte=start - ).prefetch_related("collaborators") - - # get data - while start <= end: - active_users = 0 - - books = bookings.filter( - start__lte=start, - end__gte=start - ).prefetch_related("collaborators") - - for booking in books: - active_users += booking.collaborators.all().count() + 1 - - x.append(str(start.month) + '-' + str(start.day)) - y.append(books.count()) - - step_profiles = Counter([ - str(config.profile) - for book in books - for config in book.resource.template.getConfigs() - ]) - - for profile in ResourceProfile.objects.all(): - profiles[str(profile)].append(step_profiles[str(profile)]) - users.append(active_users) - - start += timedelta(hours=12) - - in_use = len(ResourceQuery.filter(working=True, booked=True)) - not_in_use = len(ResourceQuery.filter(working=True, booked=False)) - maintenance = len(ResourceQuery.filter(working=False)) - - projects = [x.project for x in bookings] - proj_count = sorted(Counter(projects).items(), key=lambda x: x[1]) - - project_keys = [proj[0] for proj in proj_count[-5:]] - project_keys = ['None' if x is None else x for x in project_keys] - project_counts = [proj[1] for proj in proj_count[-5:]] - - resources = {key: [x, value] for key, value in profiles.items()} - - return { - "resources": resources, - "booking": [x, y], - "user": [x, users], - "utils": [in_use, not_in_use, maintenance], - "projects": [project_keys, project_counts], - "colors": anuket_colors if os.environ.get('TEMPLATE_OVERRIDE_DIR') == 'laas' else lfedge_colors - } diff --git a/src/booking/tests/__init__.py b/src/booking/tests/__init__.py deleted file mode 100644 index b6fef6c..0000000 --- a/src/booking/tests/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Max Breitenfeldt and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## diff --git a/src/booking/tests/test_models.py b/src/booking/tests/test_models.py deleted file mode 100644 index 37eb655..0000000 --- a/src/booking/tests/test_models.py +++ /dev/null @@ -1,210 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Max Breitenfeldt and others. -# Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - - -from datetime import timedelta - -from django.contrib.auth.models import User -from django.test import TestCase -from django.utils import timezone - -from booking.models import Booking -from dashboard.testing_utils import make_resource_template, make_user - - -class BookingModelTestCase(TestCase): - """ - Test the Booking model. - - Creates all the scafolding needed and tests the Booking model - """ - - def setUp(self): - """ - Prepare for Booking model tests. - - Creates all the needed models, such as users, resources, and configurations - """ - self.owner = User.objects.create(username='owner') - self.res1 = make_resource_template(name="Test template 1") - self.res2 = make_resource_template(name="Test template 2") - self.user1 = make_user(username='user1') - - def test_start_end(self): - """ - Verify the start and end fields. - - if the start of a booking is greater or equal then the end, - saving should raise a ValueException - """ - start = timezone.now() - end = start - timedelta(weeks=1) - self.assertRaises( - ValueError, - Booking.objects.create, - start=start, - end=end, - resource=self.res1, - owner=self.user1, - ) - end = start - self.assertRaises( - ValueError, - Booking.objects.create, - start=start, - end=end, - resource=self.res1, - owner=self.user1, - ) - - def test_conflicts(self): - """ - Verify conflicting dates are dealt with. - - saving an overlapping booking on the same resource - should raise a ValueException - saving for different resources should succeed - """ - start = timezone.now() - end = start + timedelta(weeks=1) - self.assertTrue( - Booking.objects.create( - start=start, - end=end, - owner=self.user1, - resource=self.res1, - ) - ) - - self.assertRaises( - ValueError, - Booking.objects.create, - start=start, - end=end, - resource=self.res1, - owner=self.user1, - ) - - self.assertRaises( - ValueError, - Booking.objects.create, - start=start + timedelta(days=1), - end=end - timedelta(days=1), - resource=self.res1, - owner=self.user1, - ) - - self.assertRaises( - ValueError, - Booking.objects.create, - start=start - timedelta(days=1), - end=end, - resource=self.res1, - owner=self.user1, - ) - - self.assertRaises( - ValueError, - Booking.objects.create, - start=start - timedelta(days=1), - end=end - timedelta(days=1), - resource=self.res1, - owner=self.user1, - ) - - self.assertRaises( - ValueError, - Booking.objects.create, - start=start, - end=end + timedelta(days=1), - resource=self.res1, - owner=self.user1, - ) - - self.assertRaises( - ValueError, - Booking.objects.create, - start=start + timedelta(days=1), - end=end + timedelta(days=1), - resource=self.res1, - owner=self.user1, - ) - - self.assertTrue( - Booking.objects.create( - start=start - timedelta(days=1), - end=start, - owner=self.user1, - resource=self.res1, - ) - ) - - self.assertTrue( - Booking.objects.create( - start=end, - end=end + timedelta(days=1), - owner=self.user1, - resource=self.res1, - ) - ) - - self.assertTrue( - Booking.objects.create( - start=start - timedelta(days=2), - end=start - timedelta(days=1), - owner=self.user1, - resource=self.res1, - ) - ) - - self.assertTrue( - Booking.objects.create( - start=end + timedelta(days=1), - end=end + timedelta(days=2), - owner=self.user1, - resource=self.res1, - ) - ) - - self.assertTrue( - Booking.objects.create( - start=start, - end=end, - owner=self.user1, - resource=self.res2, - ) - ) - - def test_extensions(self): - """ - Test booking extensions. - - saving a booking with an extended end time is allows to happen twice, - and each extension must be a maximum of one week long - """ - start = timezone.now() - end = start + timedelta(weeks=1) - self.assertTrue( - Booking.objects.create( - start=start, - end=end, - owner=self.user1, - resource=self.res1, - ) - ) - - booking = Booking.objects.all().first() # should be only thing in db - - self.assertEquals(booking.ext_count, 2) - booking.end = booking.end + timedelta(days=3) - try: - booking.save() - except Exception: - self.fail("save() threw an exception") diff --git a/src/booking/tests/test_quick_booking.py b/src/booking/tests/test_quick_booking.py deleted file mode 100644 index f405047..0000000 --- a/src/booking/tests/test_quick_booking.py +++ /dev/null @@ -1,180 +0,0 @@ -############################################################################## -# Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - -import datetime -import json - -from django.test import TestCase, Client - -from booking.models import Booking -from dashboard.testing_utils import ( - make_user, - make_user_profile, - make_lab, - make_image, - make_os, - make_opnfv_role, - make_public_net, - make_resource_template, - make_server -) - - -class QuickBookingValidFormTestCase(TestCase): - @classmethod - def setUpTestData(cls): - cls.user = make_user(False, username="newtestuser") - cls.user.set_password("testpassword") - cls.user.save() - make_user_profile(cls.user, True) - - cls.lab = make_lab() - - cls.res_template = make_resource_template(owner=cls.user, lab=cls.lab) - cls.res_profile = cls.res_template.getConfigs()[0].profile - os = make_os() - cls.image = make_image(cls.res_profile, lab=cls.lab, owner=cls.user, os=os) - cls.server = make_server(cls.res_profile, cls.lab) - cls.role = make_opnfv_role() - cls.pubnet = make_public_net(10, cls.lab) - - cls.post_data = cls.build_post_data() - cls.client = Client() - - @classmethod - def build_post_data(cls): - return { - 'filter_field': json.dumps({ - "resource": { - "resource_" + str(cls.res_profile.id): { - "selected": True, - "id": cls.res_template.id - } - }, - "lab": { - "lab_" + str(cls.lab.lab_user.id): { - "selected": True, - "id": cls.lab.lab_user.id - } - } - }), - 'purpose': 'my_purpose', - 'project': 'my_project', - 'length': '3', - 'ignore_this': 1, - 'users': '', - 'hostname': 'my_host', - 'image': str(cls.image.id), - } - - def post(self, changed_fields={}): - payload = self.post_data.copy() - payload.update(changed_fields) - response = self.client.post('/booking/quick/', payload) - return response - - def setUp(self): - self.client.login(username="newtestuser", password="testpassword") - - def assertValidBooking(self, booking): - self.assertEqual(booking.owner, self.user) - self.assertEqual(booking.purpose, 'my_purpose') - self.assertEqual(booking.project, 'my_project') - delta = booking.end - booking.start - delta -= datetime.timedelta(days=3) - self.assertLess(delta, datetime.timedelta(minutes=1)) - - resource_bundle = booking.resource - - host = resource_bundle.get_resources()[0] - self.assertEqual(host.profile, self.res_profile) - self.assertEqual(host.name, 'my_host') - - def test_with_too_long_length(self): - response = self.post({'length': '22'}) - - self.assertEqual(response.status_code, 200) - self.assertIsNone(Booking.objects.first()) - - def test_with_negative_length(self): - response = self.post({'length': '-1'}) - - self.assertEqual(response.status_code, 200) - self.assertIsNone(Booking.objects.first()) - - def test_with_invalid_installer(self): - response = self.post({'installer': str(self.installer.id + 100)}) - - self.assertEqual(response.status_code, 200) - self.assertIsNone(Booking.objects.first()) - - def test_with_invalid_scenario(self): - response = self.post({'scenario': str(self.scenario.id + 100)}) - - self.assertEqual(response.status_code, 200) - self.assertIsNone(Booking.objects.first()) - - def test_with_invalid_host_id(self): - response = self.post({'filter_field': json.dumps({ - "resource": { - "resource_" + str(self.res_profile.id + 100): { - "selected": True, - "id": self.res_profile.id + 100 - } - }, - "lab": { - "lab_" + str(self.lab.lab_user.id): { - "selected": True, - "id": self.lab.lab_user.id - } - } - })}) - - self.assertEqual(response.status_code, 200) - self.assertIsNone(Booking.objects.first()) - - def test_with_invalid_lab_id(self): - response = self.post({'filter_field': json.dumps({ - "resource": { - "resource_" + str(self.res_profile.id): { - "selected": True, - "id": self.res_profile.id - } - }, - "lab": { - "lab_" + str(self.lab.lab_user.id + 100): { - "selected": True, - "id": self.lab.lab_user.id + 100 - } - } - })}) - - self.assertEqual(response.status_code, 200) - self.assertIsNone(Booking.objects.first()) - - def test_with_invalid_empty_filter_field(self): - response = self.post({'filter_field': ''}) - - self.assertEqual(response.status_code, 200) - self.assertIsNone(Booking.objects.first()) - - def test_with_garbage_users_field(self): # expected behavior: treat as though field is empty if it has garbage data - response = self.post({'users': ['X�]QP�槰DP�+m���h�U�_�yJA:.rDi��QN|.��C��n�P��F!��D�����5ȅj�9�LV��']}) # output from /dev/urandom - - self.assertEqual(response.status_code, 200) - booking = Booking.objects.first() - self.assertIsNone(booking) - - def test_with_valid_form(self): - response = self.post() - - self.assertEqual(response.status_code, 302) # success should redirect - booking = Booking.objects.first() - self.assertIsNotNone(booking) - self.assertValidBooking(booking) diff --git a/src/booking/tests/test_stats.py b/src/booking/tests/test_stats.py deleted file mode 100644 index 5501355..0000000 --- a/src/booking/tests/test_stats.py +++ /dev/null @@ -1,59 +0,0 @@ -############################################################################# -# Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, Sean Smith, and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## -import pytz -from datetime import timedelta, datetime - -from django.test import TestCase - -from booking.models import Booking -from booking.stats import StatisticsManager as sm -from dashboard.testing_utils import make_user - - -class StatsTestCases(TestCase): - - def test_no_booking_outside_span(self): - now = datetime.now(pytz.utc) - - bad_date = now + timedelta(days=1200) - Booking.objects.create(start=now, end=bad_date, owner=make_user(username='jj')) - - actual = sm.getContinuousBookingTimeSeries() - dates = actual['booking'][0] - - for date in dates: - self.assertNotEqual(date, bad_date) - - def check_booking_and_user_counts(self): - now = datetime.now(pytz.utc) - - for i in range(20): - Booking.objects.create( - start=now, - end=now + timedelta(weeks=3), - owner=make_user(username='a')) - - for i in range(30): - Booking.objects.create( - start=now + timedelta(days=5), - end=now + timedelta(weeks=3, days=5), - owner=make_user(username='a')) - - for i in range(120): - Booking.objects.create( - start=now + timedelta(weeks=1), - end=now + timedelta(weeks=4), - owner=make_user(username='a')) - - dates = [[now, 20], [now + timedelta(days=5), 30], [now + timedelta(weeks=1), 120]] - actual = sm.getContinuousBookingTimeSeries() - - for date in dates: - self.assertEqual(date[1], actual['booking'][date[0]]) - self.assertEqual(date[1], actual['booking'][date[1]]) diff --git a/src/booking/urls.py b/src/booking/urls.py deleted file mode 100644 index 0b60351..0000000 --- a/src/booking/urls.py +++ /dev/null @@ -1,53 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Max Breitenfeldt and others. -# Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - - -""" -laas_dashboard URL Configuration. - -The `urlpatterns` list routes URLs to views. For more information please see: - https://docs.djangoproject.com/en/1.10/topics/http/urls/ -Examples: -Function views - 1. Add an import: from my_app import views - 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') -Class-based views - 1. Add an import: from other_app.views import Home - 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') -Including another URLconf - 1. Import the include() function: from django.conf.urls import url, include - 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) -""" -from django.conf.urls import url - -from booking.views import ( - booking_detail_view, - BookingDeleteView, - bookingDelete, - BookingListView, - booking_stats_view, - booking_stats_json, - quick_create, - booking_modify_image -) - -app_name = 'booking' -urlpatterns = [ - url(r'^detail/(?P[0-9]+)/$', booking_detail_view, name='detail'), - url(r'^(?P[0-9]+)/$', booking_detail_view, name='booking_detail'), - url(r'^delete/$', BookingDeleteView.as_view(), name='delete_prefix'), - url(r'^delete/(?P[0-9]+)/$', BookingDeleteView.as_view(), name='delete'), - url(r'^delete/(?P[0-9]+)/confirm/$', bookingDelete, name='delete_booking'), - url(r'^modify/(?P[0-9]+)/image/$', booking_modify_image, name='modify_booking_image'), - url(r'^list/$', BookingListView.as_view(), name='list'), - url(r'^stats/$', booking_stats_view, name='stats'), - url(r'^stats/json$', booking_stats_json, name='stats_json'), - url(r'^quick/$', quick_create, name='quick_create'), -] diff --git a/src/booking/views.py b/src/booking/views.py deleted file mode 100644 index 367a18d..0000000 --- a/src/booking/views.py +++ /dev/null @@ -1,211 +0,0 @@ -############################################################################## -# Copyright (c) 2016 Max Breitenfeldt and others. -# Copyright (c) 2018 Parker Berberian, Sawyer Bergeron, and others. -# -# All rights reserved. This program and the accompanying materials -# are made available under the terms of the Apache License, Version 2.0 -# which accompanies this distribution, and is available at -# http://www.apache.org/licenses/LICENSE-2.0 -############################################################################## - -from django.contrib import messages -from django.shortcuts import get_object_or_404 -from django.http import JsonResponse, HttpResponse -from django.utils import timezone -from django.views import View -from django.views.generic import TemplateView -from django.shortcuts import redirect, render -from django.db.models import Q -from django.urls import reverse - -from resource_inventory.models import ResourceBundle, ResourceProfile, Image, ResourceQuery -from account.models import Downtime, Lab -from booking.models import Booking -from booking.stats import StatisticsManager -from booking.forms import HostReImageForm -from workflow.forms import FormUtils -from api.models import JobFactory, GeneratedCloudConfig -from workflow.views import login -from booking.forms import QuickBookingForm -from booking.quick_deployer import create_from_form, drop_filter -import traceback - - -def quick_create_clear_fields(request): - request.session['quick_create_forminfo'] = None - - -def quick_create(request): - if not request.user.is_authenticated: - return login(request) - - if request.method == 'GET': - context = {} - attrs = FormUtils.getLabData(user=request.user) - context['form'] = QuickBookingForm(lab_data=attrs, default_user=request.user.username, user=request.user) - context['lab_profile_map'] = {} - context.update(drop_filter(request.user)) - context['contact_email'] = Lab.objects.filter(name="UNH_IOL").first().contact_email - return render(request, 'booking/quick_deploy.html', context) - - if request.method == 'POST': - attrs = FormUtils.getLabData(user=request.user) - form = QuickBookingForm(request.POST, lab_data=attrs, user=request.user) - - context = {} - context['lab_profile_map'] = {} - context['form'] = form - - if form.is_valid(): - try: - booking = create_from_form(form, request) - messages.success(request, "We've processed your request. " - "Check Account->My Bookings for the status of your new booking") - return redirect(reverse('booking:booking_detail', kwargs={'booking_id': booking.id})) - except Exception as e: - print("Error occurred while handling quick deployment:") - traceback.print_exc() - print(str(e)) - messages.error(request, "Whoops, an error occurred: " + str(e)) - context.update(drop_filter(request.user)) - return render(request, 'booking/quick_deploy.html', context) - else: - messages.error(request, "Looks like the form didn't validate. Check that you entered everything correctly") - context['status'] = 'false' - context.update(drop_filter(request.user)) - return render(request, 'booking/quick_deploy.html', context) - - -class BookingView(TemplateView): - template_name = "booking/booking_detail.html" - - def get_context_data(self, **kwargs): - booking = get_object_or_404(Booking, id=self.kwargs['booking_id']) - title = 'Booking Details' - contact = Lab.objects.filter(name="UNH_IOL").first().contact_email - downtime = Downtime.objects.filter(lab=booking.lab, start__lt=timezone.now, end__gt=timezone.now()).first() - context = super(BookingView, self).get_context_data(**kwargs) - context.update({ - 'title': title, - 'booking': booking, - 'downtime': downtime, - 'contact_email': contact - }) - return context - - -class BookingDeleteView(TemplateView): - template_name = "booking/booking_delete.html" - - def get_context_data(self, **kwargs): - booking = get_object_or_404(Booking, id=self.kwargs['booking_id']) - title = 'Delete Booking' - context = super(BookingDeleteView, self).get_context_data(**kwargs) - context.update({'title': title, 'booking': booking}) - return context - - -def bookingDelete(request, booking_id): - booking = get_object_or_404(Booking, id=booking_id) - booking.delete() - messages.add_message(request, messages.SUCCESS, 'Booking deleted') - return redirect('../../../../') - - -class BookingListView(TemplateView): - template_name = "booking/booking_list.html" - - def get_context_data(self, **kwargs): - bookings = Booking.objects.filter(end__gte=timezone.now()) - title = 'Search Booking' - context = super(BookingListView, self).get_context_data(**kwargs) - context.update({'title': title, 'bookings': bookings}) - return context - - -class ResourceBookingsJSON(View): - def get(self, request, *args, **kwargs): - resource = get_object_or_404(ResourceBundle, id=self.kwargs['resource_id']) - bookings = resource.booking_set.get_queryset().values( - 'id', - 'start', - 'end', - 'purpose', - 'config_bundle__name' - ) - return JsonResponse({'bookings': list(bookings)}) - - -def build_image_mapping(lab, user): - mapping = {} - for profile in ResourceProfile.objects.filter(labs=lab): - images = Image.objects.filter( - from_lab=lab, - architecture=profile.architecture - ).filter( - Q(public=True) | Q(owner=user) - ) - mapping[profile.name] = [{"name": image.name, "value": image.id} for image in images] - return mapping - - -def booking_detail_view(request, booking_id): - user = None - if request.user.is_authenticated: - user = request.user - else: - return render(request, "dashboard/login.html", {'title': 'Authentication Required'}) - - booking = get_object_or_404(Booking, id=booking_id) - allowed_users = set(list(booking.collaborators.all())) - allowed_users.add(booking.owner) - if user not in allowed_users: - return render(request, "dashboard/login.html", {'title': 'This page is private'}) - - context = { - 'title': 'Booking Details', - 'booking': booking, - 'pdf': booking.pdf, - 'user_id': user.id, - 'image_mapping': build_image_mapping(booking.lab, user), - 'posix_username': GeneratedCloudConfig._normalize_username(None, user.username) - } - - return render( - request, - "booking/booking_detail.html", - context - ) - - -def booking_modify_image(request, booking_id): - form = HostReImageForm(request.POST) - if form.is_valid(): - booking = Booking.objects.get(id=booking_id) - if request.user != booking.owner: - return HttpResponse("unauthorized") - if timezone.now() > booking.end: - return HttpResponse("unauthorized") - new_image = Image.objects.get(id=form.cleaned_data['image_id']) - host = ResourceQuery.get(id=form.cleaned_data['host_id']) - host.config.image = new_image - host.config.save() - JobFactory.reimageHost(new_image, booking, host) - return HttpResponse(new_image.name) - return HttpResponse("error") - - -def booking_stats_view(request): - return render( - request, - "booking/stats.html", - context={"data": StatisticsManager.getContinuousBookingTimeSeries(), "title": ""} - ) - - -def booking_stats_json(request): - try: - span = int(request.GET.get("days", 14)) - except Exception: - span = 14 - return JsonResponse(StatisticsManager.getContinuousBookingTimeSeries(span), safe=False) -- cgit 1.2.3-korg