diff --git a/nicohack202002/uncloud/.gitignore b/nicohack202002/uncloud/.gitignore index 49ef255..4ade18f 100644 --- a/nicohack202002/uncloud/.gitignore +++ b/nicohack202002/uncloud/.gitignore @@ -1 +1,3 @@ db.sqlite3 +uncloud/secrets.py +debug.log \ No newline at end of file diff --git a/nicohack202002/uncloud/opennebula/management/commands/syncvm.py b/nicohack202002/uncloud/opennebula/management/commands/syncvm.py index 205b066..e68a4a4 100644 --- a/nicohack202002/uncloud/opennebula/management/commands/syncvm.py +++ b/nicohack202002/uncloud/opennebula/management/commands/syncvm.py @@ -31,7 +31,7 @@ class Command(BaseCommand): user = get_user_model().objects.get(username=vm_owner) except get_user_model().DoesNotExist: user = get_user_model().objects.create_user(username=vm_owner) - + vm = json.dumps(vm, ensure_ascii=True) vm_object = VMModel.objects.create(vmid=vm_id, owner=user, data=vm) vm_object.save() else: diff --git a/nicohack202002/uncloud/opennebula/migrations/0004_auto_20200222_0713.py b/nicohack202002/uncloud/opennebula/migrations/0004_auto_20200222_0713.py new file mode 100644 index 0000000..a298c06 --- /dev/null +++ b/nicohack202002/uncloud/opennebula/migrations/0004_auto_20200222_0713.py @@ -0,0 +1,23 @@ +# Generated by Django 3.0.3 on 2020-02-22 07:13 + +from django.db import migrations, models +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('opennebula', '0003_auto_20200221_1113'), + ] + + operations = [ + migrations.RemoveField( + model_name='vm', + name='id', + ), + migrations.AddField( + model_name='vm', + name='uuid', + field=models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False), + ), + ] diff --git a/nicohack202002/uncloud/opennebula/models.py b/nicohack202002/uncloud/opennebula/models.py index cd1a044..915862a 100644 --- a/nicohack202002/uncloud/opennebula/models.py +++ b/nicohack202002/uncloud/opennebula/models.py @@ -1,8 +1,11 @@ +import uuid + from django.db import models from django.contrib.auth import get_user_model class VM(models.Model): + uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) vmid = models.IntegerField() owner = models.ForeignKey(get_user_model(), on_delete=models.CASCADE) data = models.CharField(max_length=65536, null=True) diff --git a/nicohack202002/uncloud/opennebula/serializers.py b/nicohack202002/uncloud/opennebula/serializers.py index c84f2ab..ac40725 100644 --- a/nicohack202002/uncloud/opennebula/serializers.py +++ b/nicohack202002/uncloud/opennebula/serializers.py @@ -5,4 +5,4 @@ from opennebula.models import VM class VMSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = VM - fields = ['vmid', 'owner', 'data'] + fields = ['uuid', 'vmid', 'owner', 'data'] diff --git a/nicohack202002/uncloud/opennebula/views.py b/nicohack202002/uncloud/opennebula/views.py index f706815..1030101 100644 --- a/nicohack202002/uncloud/opennebula/views.py +++ b/nicohack202002/uncloud/opennebula/views.py @@ -1,14 +1,59 @@ -from rest_framework import viewsets, generics +import json + +from rest_framework import generics +from rest_framework.authentication import SessionAuthentication, BasicAuthentication +from rest_framework.permissions import IsAuthenticated, IsAdminUser + from .models import VM from .serializers import VMSerializer - class VMList(generics.ListAPIView): + authentication_classes = [SessionAuthentication, BasicAuthentication] + permission_classes = [IsAuthenticated, IsAdminUser] queryset = VM.objects.all() serializer_class = VMSerializer class VMDetail(generics.RetrieveAPIView): - lookup_field = 'vmid' + authentication_classes = [SessionAuthentication, BasicAuthentication] + permission_classes = [IsAuthenticated, IsAdminUser] + lookup_field = 'uuid' queryset = VM.objects.all() serializer_class = VMSerializer + + +class UserVMList(generics.ListAPIView): + authentication_classes = [SessionAuthentication, BasicAuthentication] + permission_classes = [IsAuthenticated] + serializer_class = VMSerializer + + def get_queryset(self): + user_email = self.request.user.ldap_user.attrs.data['mail'] + vms = [] + for mail in user_email: + vms += VM.objects.filter(owner__username=mail) + + for vm in vms: + data = json.loads(vm.data) + vm_template = data['TEMPLATE'] + vm.data = { + 'cpu': vm_template['VCPU'], + 'ram': vm_template['MEMORY'], + 'nic': vm_template['NIC'], + 'disks': vm_template['DISK'] + } + + return vms + +####################################### +# Following for quick experimentation # +####################################### + +# from django.http import HttpResponse +# +# def test(request): +# user_email = request.user.ldap_user.attrs.data['mail'] +# vms = [] +# for mail in user_email: +# vms += VM.objects.filter(owner__username=mail) +# return HttpResponse("Hello World") diff --git a/nicohack202002/uncloud/uncloud/secrets_sample.py b/nicohack202002/uncloud/uncloud/secrets_sample.py index e094e2d..f4c89ac 100644 --- a/nicohack202002/uncloud/uncloud/secrets_sample.py +++ b/nicohack202002/uncloud/uncloud/secrets_sample.py @@ -6,3 +6,7 @@ OPENNEBULA_URL = 'https://opennebula.ungleich.ch:2634/RPC2' # user:pass for accessing opennebula OPENNEBULA_USER_PASS = 'user:password' + +AUTH_LDAP_BIND_DN = 'something' + +AUTH_LDAP_BIND_PASSWORD = r'somepass' diff --git a/nicohack202002/uncloud/uncloud/settings.py b/nicohack202002/uncloud/uncloud/settings.py index 1e8f358..edd7c19 100644 --- a/nicohack202002/uncloud/uncloud/settings.py +++ b/nicohack202002/uncloud/uncloud/settings.py @@ -12,6 +12,15 @@ https://docs.djangoproject.com/en/3.0/ref/settings/ import os +import stripe +import ldap + +import uncloud.secrets as secrets + +from django_auth_ldap.config import LDAPSearch + + + # Build paths inside the project like this: os.path.join(BASE_DIR, ...) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) @@ -106,14 +115,14 @@ AUTH_PASSWORD_VALIDATORS = [ ################################################################################ # AUTH/LDAP -import ldap -from django_auth_ldap.config import LDAPSearch, LDAPSearchUnion - - AUTH_LDAP_SERVER_URI = "ldaps://ldap1.ungleich.ch,ldaps://ldap2.ungleich.ch" AUTH_LDAP_USER_DN_TEMPLATE = "uid=%(user)s,ou=customer,dc=ungleich,dc=ch" +AUTH_LDAP_BIND_DN = secrets.AUTH_LDAP_BIND_DN + +AUTH_LDAP_BIND_PASSWORD = secrets.AUTH_LDAP_BIND_PASSWORD + AUTH_LDAP_USER_SEARCH = LDAPSearch( "ou=customer,dc=ungleich,dc=ch", ldap.SCOPE_SUBTREE, "(uid=%(user)s)" ) @@ -132,7 +141,6 @@ AUTH_USER_MODEL = 'uncloud_auth.User' # AUTH/REST REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ - 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', ] } @@ -158,9 +166,28 @@ USE_TZ = True STATIC_URL = '/static/' +stripe.api_key = secrets.STRIPE_KEY -# Uncommitted file -# import uncloud.secrets -# -# import stripe -# stripe.api_key = uncloud.secrets.STRIPE_KEY +LOGGING = { + 'version': 1, + 'disable_existing_loggers': False, + 'handlers': { + 'file': { + 'level': 'DEBUG', + 'class': 'logging.FileHandler', + 'filename': 'debug.log', + }, + }, + 'loggers': { + 'django': { + 'handlers': ['file'], + 'level': 'DEBUG', + 'propagate': True, + }, + 'django_auth_ldap': { + 'handlers': ['file'], + 'level': 'DEBUG', + 'propagate': True + } + }, +} diff --git a/nicohack202002/uncloud/uncloud/urls.py b/nicohack202002/uncloud/uncloud/urls.py index c7ce9b6..cd8c333 100644 --- a/nicohack202002/uncloud/uncloud/urls.py +++ b/nicohack202002/uncloud/uncloud/urls.py @@ -32,7 +32,7 @@ urlpatterns = [ path('admin/', admin.site.urls), path('products/', views.ProductsView.as_view(), name='products'), path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), - path('vm/list/', oneviews.VMList.as_view(), name='vm_list'), - path('vm/detail//', oneviews.VMDetail.as_view(), name='vm_detail'), - + path('opennebula/vm/list/', oneviews.VMList.as_view(), name='vm_list'), + path('opennebula/vm/detail//', oneviews.VMDetail.as_view(), name='vm_detail'), + path('vm/list/', oneviews.UserVMList.as_view(), name='user_vm_list'), ] diff --git a/nicohack202002/uncloud/uncloud_api/migrations/0002_auto_20200222_0719.py b/nicohack202002/uncloud/uncloud_api/migrations/0002_auto_20200222_0719.py new file mode 100644 index 0000000..a52eade --- /dev/null +++ b/nicohack202002/uncloud/uncloud_api/migrations/0002_auto_20200222_0719.py @@ -0,0 +1,46 @@ +# Generated by Django 3.0.3 on 2020-02-22 07:19 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('uncloud_api', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='VMSnapshotOrder', + fields=[ + ('order_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='uncloud_api.Order')), + ], + bases=('uncloud_api.order',), + ), + migrations.CreateModel( + name='VMSnapshotProduct', + fields=[ + ('product_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='uncloud_api.Product')), + ('gb_ssd', models.FloatField()), + ('gb_hdd', models.FloatField()), + ], + bases=('uncloud_api.product',), + ), + migrations.DeleteModel( + name='OrderReference', + ), + migrations.RemoveField( + model_name='product', + name='name', + ), + migrations.RemoveField( + model_name='product', + name='recurring_period', + ), + migrations.AddField( + model_name='product', + name='status', + field=models.CharField(choices=[('pending', 'Pending'), ('being_created', 'Being created'), ('created_active', 'Created'), ('deleted', 'Deleted')], default='pending', max_length=256), + ), + ] diff --git a/nicohack202002/uncloud/uncloud_api/models.py b/nicohack202002/uncloud/uncloud_api/models.py index fafefe6..7eaec7b 100644 --- a/nicohack202002/uncloud/uncloud_api/models.py +++ b/nicohack202002/uncloud/uncloud_api/models.py @@ -31,18 +31,21 @@ from django.contrib.auth import get_user_model # logs # Should have a log = ... => 1:n field for most models! + class Product(models.Model): # override these fields by default description = "" recurring_period = "not_recurring" - - status = models.CharField(max_length=256, - choices = ( - ('pending', 'Pending'), - ('being_created', 'Being created'), - ('created_active', 'Created'), - ('deleted', 'Deleted') - ) + uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + status = models.CharField( + max_length=256, choices=( + ('pending', 'Pending'), + ('being_created', 'Being created'), + ('created_active', 'Created'), + ('deleted', 'Deleted') + ), + default='pending' + ) def __str__(self): return "{}".format(self.name) @@ -86,7 +89,6 @@ Sample price for a VM with {} GB SSD and {} GB HDD VM is: {}. gb_hdd = models.FloatField() - class Feature(models.Model): uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) name = models.CharField(max_length=256) diff --git a/notes-abk.md b/notes-abk.md new file mode 100644 index 0000000..6d5c223 --- /dev/null +++ b/notes-abk.md @@ -0,0 +1,11 @@ +## TODO 2020-02-22 + +* ~~move the current rest api to /opennebula~~ +* ~~make the /opennebula api only accessible by an admin account~~ +* ~~create a new filtered api on /vm/list that~~ + * ~~a) requires authentication~~ + * ~~b) only shows the VMs of the current user~~ +* ~~the new api should not contain all details, but: cpus (as read by the vcpu field), ram, ips, disks~~ +* ~~also make a (random) uuid the primary key for VMs - everything in this uncloud hack will use uuids as the id~~ +* ~~still expose the opennebula id as opennebula_id~~ +* ~~note put all secrets/configs into uncloud.secrets - I added a sample file into the repo~~ diff --git a/notes.org b/notes.org deleted file mode 100644 index 72e8ffc..0000000 --- a/notes.org +++ /dev/null @@ -1 +0,0 @@ -*