aboutsummaryrefslogtreecommitdiffstats
path: root/src/account
diff options
context:
space:
mode:
authorParker Berberian <pberberian@iol.unh.edu>2018-10-10 16:06:47 -0400
committerParker Berberian <pberberian@iol.unh.edu>2018-10-15 13:16:11 -0400
commit1f3a770d2547848590f39e9d9b9bdffeb94eec14 (patch)
tree97222e5facd1a242d951c38482315057b5790d51 /src/account
parent6d4019e59eda897384e9c00d1daf8b2ce87d128f (diff)
Lab as a Service 2.0
See changes here: https://wiki.opnfv.org/display/INF/Pharos+Laas Change-Id: I59ada5f98e70a28d7f8c14eab3239597e236ca26 Signed-off-by: Sawyer Bergeron <sbergeron@iol.unh.edu> Signed-off-by: Parker Berberian <pberberian@iol.unh.edu>
Diffstat (limited to 'src/account')
-rw-r--r--src/account/admin.py5
-rw-r--r--src/account/migrations/0001_initial.py33
-rw-r--r--src/account/migrations/0002_auto_20180110_1636.py33
-rw-r--r--src/account/migrations/0002_lab_description.py19
-rw-r--r--src/account/migrations/0003_auto_20180110_1639.py24
-rw-r--r--src/account/migrations/0003_publicnetwork.py25
-rw-r--r--src/account/migrations/__init__.py10
-rw-r--r--src/account/models.py127
-rw-r--r--src/account/tasks.py4
-rw-r--r--src/account/urls.py7
-rw-r--r--src/account/views.py48
11 files changed, 262 insertions, 73 deletions
diff --git a/src/account/admin.py b/src/account/admin.py
index 6f77122..b4c142c 100644
--- a/src/account/admin.py
+++ b/src/account/admin.py
@@ -1,5 +1,6 @@
##############################################################################
# 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
@@ -10,7 +11,9 @@
from django.contrib import admin
-from account.models import UserProfile, Lab
+from account.models import UserProfile, Lab, VlanManager, PublicNetwork
admin.site.register(UserProfile)
admin.site.register(Lab)
+admin.site.register(VlanManager)
+admin.site.register(PublicNetwork)
diff --git a/src/account/migrations/0001_initial.py b/src/account/migrations/0001_initial.py
index 591f702..c8b5bdc 100644
--- a/src/account/migrations/0001_initial.py
+++ b/src/account/migrations/0001_initial.py
@@ -1,6 +1,4 @@
-# -*- coding: utf-8 -*-
-# Generated by Django 1.10 on 2016-11-03 13:33
-from __future__ import unicode_literals
+# Generated by Django 2.1 on 2018-09-14 14:48
import account.models
from django.conf import settings
@@ -18,21 +16,50 @@ class Migration(migrations.Migration):
operations = [
migrations.CreateModel(
+ name='Lab',
+ fields=[
+ ('name', models.CharField(max_length=200, primary_key=True, serialize=False, unique=True)),
+ ('contact_email', models.EmailField(blank=True, max_length=200, null=True)),
+ ('contact_phone', models.CharField(blank=True, max_length=20, null=True)),
+ ('status', models.IntegerField(default=0)),
+ ('location', models.TextField(default='unknown')),
+ ('api_token', models.CharField(max_length=50)),
+ ('lab_user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
+ ],
+ ),
+ migrations.CreateModel(
name='UserProfile',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('timezone', models.CharField(default='UTC', max_length=100)),
('ssh_public_key', models.FileField(blank=True, null=True, upload_to=account.models.upload_to)),
('pgp_public_key', models.FileField(blank=True, null=True, upload_to=account.models.upload_to)),
+ ('email_addr', models.CharField(default='email@mail.com', max_length=300)),
('company', models.CharField(max_length=200)),
('oauth_token', models.CharField(max_length=1024)),
('oauth_secret', models.CharField(max_length=1024)),
('jira_url', models.CharField(default='', max_length=100)),
('full_name', models.CharField(default='', max_length=100)),
+ ('booking_privledge', models.BooleanField(default=False)),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'db_table': 'user_profile',
},
),
+ migrations.CreateModel(
+ name='VlanManager',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('vlans', models.TextField()),
+ ('block_size', models.IntegerField()),
+ ('allow_overlapping', models.BooleanField()),
+ ('reserved_vlans', models.TextField()),
+ ],
+ ),
+ migrations.AddField(
+ model_name='lab',
+ name='vlan_manager',
+ field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='account.VlanManager'),
+ ),
]
diff --git a/src/account/migrations/0002_auto_20180110_1636.py b/src/account/migrations/0002_auto_20180110_1636.py
deleted file mode 100644
index 6170acb..0000000
--- a/src/account/migrations/0002_auto_20180110_1636.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# -*- coding: utf-8 -*-
-# Generated by Django 1.10 on 2018-01-10 16:36
-from __future__ import unicode_literals
-
-from django.conf import settings
-from django.db import migrations, models
-import django.db.models.deletion
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- migrations.swappable_dependency(settings.AUTH_USER_MODEL),
- ('account', '0001_initial'),
- ]
-
- operations = [
- migrations.CreateModel(
- name='Lab',
- fields=[
- ('id', models.CharField(max_length=200, primary_key=True, serialize=False)),
- ('name', models.CharField(max_length=200, unique=True)),
- ('contact_email', models.EmailField(blank=True, max_length=200, null=True)),
- ('contact_phone', models.CharField(blank=True, max_length=20, null=True)),
- ('lab_user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
- ],
- ),
- migrations.AddField(
- model_name='userprofile',
- name='email_addr',
- field=models.CharField(default='email@mail.com', max_length=300),
- ),
- ]
diff --git a/src/account/migrations/0002_lab_description.py b/src/account/migrations/0002_lab_description.py
new file mode 100644
index 0000000..445501a
--- /dev/null
+++ b/src/account/migrations/0002_lab_description.py
@@ -0,0 +1,19 @@
+# Generated by Django 2.1 on 2018-09-14 20:22
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('account', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='lab',
+ name='description',
+ field=models.CharField(default='Lab description default', max_length=240),
+ preserve_default=False,
+ ),
+ ]
diff --git a/src/account/migrations/0003_auto_20180110_1639.py b/src/account/migrations/0003_auto_20180110_1639.py
deleted file mode 100644
index d0bc4d6..0000000
--- a/src/account/migrations/0003_auto_20180110_1639.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# -*- coding: utf-8 -*-
-# Generated by Django 1.10 on 2018-01-10 16:39
-from __future__ import unicode_literals
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('account', '0002_auto_20180110_1636'),
- ]
-
- operations = [
- migrations.RemoveField(
- model_name='lab',
- name='id',
- ),
- migrations.AlterField(
- model_name='lab',
- name='name',
- field=models.CharField(max_length=200, primary_key=True, serialize=False, unique=True),
- ),
- ]
diff --git a/src/account/migrations/0003_publicnetwork.py b/src/account/migrations/0003_publicnetwork.py
new file mode 100644
index 0000000..71e5caa
--- /dev/null
+++ b/src/account/migrations/0003_publicnetwork.py
@@ -0,0 +1,25 @@
+# Generated by Django 2.1 on 2018-09-26 14:41
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('account', '0002_lab_description'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='PublicNetwork',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('vlan', models.IntegerField()),
+ ('in_use', models.BooleanField(default=False)),
+ ('cidr', models.CharField(default='0.0.0.0/0', max_length=50)),
+ ('gateway', models.CharField(default='0.0.0.0', max_length=50)),
+ ('lab', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='account.Lab')),
+ ],
+ ),
+ ]
diff --git a/src/account/migrations/__init__.py b/src/account/migrations/__init__.py
index b5914ce..e69de29 100644
--- a/src/account/migrations/__init__.py
+++ b/src/account/migrations/__init__.py
@@ -1,10 +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/account/models.py b/src/account/models.py
index aad4c50..18a8cbb 100644
--- a/src/account/models.py
+++ b/src/account/models.py
@@ -10,6 +10,14 @@
from django.contrib.auth.models import User
from django.db import models
+import json
+import random
+
+
+class LabStatus(object):
+ UP = 0
+ TEMP_DOWN = 100
+ DOWN = 200
def upload_to(object, filename):
@@ -28,6 +36,7 @@ class UserProfile(models.Model):
jira_url = models.CharField(max_length=100, default='')
full_name = models.CharField(max_length=100, default='')
+ booking_privledge = models.BooleanField(default=False)
class Meta:
db_table = 'user_profile'
@@ -35,11 +44,129 @@ class UserProfile(models.Model):
def __str__(self):
return self.user.username
+
+class VlanManager(models.Model):
+ # list of length 4096 containing either 0 (not available) or 1 (available)
+ vlans = models.TextField()
+ block_size = models.IntegerField()
+ allow_overlapping = models.BooleanField()
+ # list of length 4096 containing either 0 (not rexerved) or 1 (reserved)
+ reserved_vlans = models.TextField()
+
+ def get_vlan(self, count=1):
+ allocated = []
+ vlans = json.loads(self.vlans)
+ for i in range(count):
+ new_vlan = vlans.index(1) # will throw if none available
+ vlans[new_vlan] = 0
+ allocated.append(new_vlan)
+ if count is 1:
+ return allocated[0]
+ return allocated
+
+ def get_public_vlan(self):
+ return PublicNetwork.objects.filter(lab=self.lab_set.first(), in_use=False).first()
+
+ def reserve_public_vlan(self, vlan):
+ net = PublicNetwork.objects.get(lab=self.lab_set.first(), vlan=vlan, in_use=False)
+ net.in_use = True
+ net.save()
+
+ def release_public_vlan(self, vlan):
+ net = PublicNetwork.objects.get(lab=self.lab_set.first(), vlan=vlan, in_use=True)
+ net.in_use = False
+ net.save()
+
+ def public_vlan_is_available(self, vlan):
+ net = PublicNetwork.objects.get(lab=self.lab_set.first(), vlan=vlan)
+ return not net.in_use
+
+
+ def is_available(self, vlans):
+ """
+ 'vlans' is either a single vlan id integer or a list of integers
+ will return true (available) or false
+ """
+ if self.allow_overlapping:
+ return True
+
+ reserved = json.loads(self.reserved_vlans)
+ vlan_master_list = json.loads(self.vlans)
+ try:
+ iter(vlans)
+ except:
+ vlans = [vlans]
+
+ for vlan in vlans:
+ if not vlan_master_list[vlan] or reserved[vlan]:
+ return False
+ return True
+
+ def release_vlans(self, vlans):
+ """
+ 'vlans' is either a single vlan id integer or a list of integers
+ will make the vlans available
+ doesnt return a value
+ """
+ my_vlans = json.loads(self.vlans)
+
+ try:
+ iter(vlans)
+ except:
+ vlans = [vlans]
+
+ for vlan in vlans:
+ my_vlans[vlan] = 1
+ self.vlans = json.dumps(my_vlans)
+ self.save()
+
+ def reserve_vlans(self, vlans):
+ my_vlans = json.loads(self.vlans)
+
+ try:
+ iter(vlans)
+ except:
+ vlans = [vlans]
+
+ vlans = set(vlans)
+
+ for vlan in vlans:
+ if my_vlans[vlan] is 0:
+ raise ValueError("vlan " + str(vlan) + " is not available")
+
+ my_vlans[vlan] = 0
+ self.vlans = json.dumps(my_vlans)
+ self.save()
+
+
+
class Lab(models.Model):
lab_user = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=200, primary_key=True, unique=True, null=False, blank=False)
contact_email = models.EmailField(max_length=200, null=True, blank=True)
contact_phone = models.CharField(max_length=20, null=True, blank=True)
+ status = models.IntegerField(default=LabStatus.UP)
+ vlan_manager = models.ForeignKey(VlanManager, on_delete=models.CASCADE, null=True)
+ location = models.TextField(default="unknown")
+ api_token = models.CharField(max_length=50)
+ description = models.CharField(max_length=240)
+
+ @staticmethod
+ def make_api_token():
+ alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+ key = ""
+ for i in range(45):
+ key += random.choice(alphabet)
+ return key
+
def __str__(self):
return self.name
+
+
+class PublicNetwork(models.Model):
+ vlan = models.IntegerField()
+ lab = models.ForeignKey(Lab, on_delete=models.CASCADE)
+ in_use = models.BooleanField(default=False)
+ cidr = models.CharField(max_length=50, default="0.0.0.0/0")
+ gateway = models.CharField(max_length=50, default="0.0.0.0")
diff --git a/src/account/tasks.py b/src/account/tasks.py
index bfb865d..fe51974 100644
--- a/src/account/tasks.py
+++ b/src/account/tasks.py
@@ -1,5 +1,6 @@
##############################################################################
# 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
@@ -28,7 +29,6 @@ def sync_jira_accounts():
user.email = user_dict['emailAddress']
user.userprofile.url = user_dict['self']
user.userprofile.full_name = user_dict['displayName']
- print(user_dict)
user.userprofile.save()
- user.save() \ No newline at end of file
+ user.save()
diff --git a/src/account/urls.py b/src/account/urls.py
index 3962a0c..6ce2115 100644
--- a/src/account/urls.py
+++ b/src/account/urls.py
@@ -1,5 +1,6 @@
##############################################################################
# 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
@@ -27,10 +28,16 @@ from django.conf.urls import url
from account.views import *
+app_name = "account"
urlpatterns = [
url(r'^settings/', AccountSettingsView.as_view(), name='settings'),
url(r'^authenticated/$', JiraAuthenticatedView.as_view(), name='authenticated'),
url(r'^login/$', JiraLoginView.as_view(), name='login'),
url(r'^logout/$', JiraLogoutView.as_view(), name='logout'),
url(r'^users/$', UserListView.as_view(), name='users'),
+ url(r'^my/resources', account_resource_view, name="my-resources"),
+ url(r'^my/bookings', account_booking_view, name="my-bookings"),
+ url(r'^my/images', account_images_view, name="my-images"),
+ url(r'^my/configurations', account_configuration_view, name="my-configurations"),
+ url(r'^my/$', account_detail_view, name="my-account"),
]
diff --git a/src/account/views.py b/src/account/views.py
index e6a0e5d..04d21b8 100644
--- a/src/account/views.py
+++ b/src/account/views.py
@@ -1,5 +1,6 @@
##############################################################################
# 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
@@ -21,12 +22,15 @@ from django.contrib.auth.models import User
from django.urls import reverse
from django.utils.decorators import method_decorator
from django.views.generic import RedirectView, TemplateView, UpdateView
+from django.shortcuts import render
from jira import JIRA
from rest_framework.authtoken.models import Token
from account.forms import AccountSettingsForm
from account.jira_util import SignatureMethod_RSA_SHA1
from account.models import UserProfile
+from booking.models import Booking
+from resource_inventory.models import GenericResourceBundle, ConfigBundle, Image
@method_decorator(login_required, name='dispatch')
@@ -153,3 +157,47 @@ class UserListView(TemplateView):
context = super(UserListView, self).get_context_data(**kwargs)
context.update({'title': "Dashboard Users", 'users': users})
return context
+
+
+def account_detail_view(request):
+ template = "account/details.html"
+ return render(request, template)
+
+def account_resource_view(request):
+ """
+ gathers a users genericResoureBundles and
+ turns them into displayable objects
+ """
+ if not request.user.is_authenticated:
+ return render(request, "dashboard/login.html", {'title': 'Authentication Required'})
+ template = "account/resource_list.html"
+ resources = list(GenericResourceBundle.objects.filter(owner=request.user))
+ context = {"resources": resources, "title": "My Resources"}
+ return render(request, template, context=context)
+
+def account_booking_view(request):
+ if not request.user.is_authenticated:
+ return render(request, "dashboard/login.html", {'title': 'Authentication Required'})
+ template = "account/booking_list.html"
+ bookings = list(Booking.objects.filter(owner=request.user))
+ collab_bookings = list(request.user.collaborators.all())
+ context = {"title": "My Bookings", "bookings": bookings, "collab_bookings": collab_bookings}
+ return render(request, template, context=context)
+
+def account_configuration_view(request):
+ if not request.user.is_authenticated:
+ return render(request, "dashboard/login.html", {'title': 'Authentication Required'})
+ template = "account/configuration_list.html"
+ configs = list(ConfigBundle.objects.filter(owner=request.user))
+ context = {"title": "Configuration List", "configurations": configs}
+ return render(request, template, context=context)
+
+def account_images_view(request):
+ if not request.user.is_authenticated:
+ return render(request, "dashboard/login.html", {'title': 'Authentication Required'})
+ template = "account/image_list.html"
+ my_images = Image.objects.filter(owner=request.user)
+ public_images = Image.objects.filter(public=True)
+ context = {"title": "Images", "images": my_images, "public_images": public_images }
+ return render(request, template, context=context)
+