Commit 08b546b9 authored by CAMPION Sebastien's avatar CAMPION Sebastien

Runner model and first views

parent f148cba3
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-18 07:48
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):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='AllgoUser',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('sshkey', models.CharField(max_length=40)),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='allgouser', to=settings.AUTH_USER_MODEL)),
],
options={
'db_table': 'dj_users',
},
),
migrations.CreateModel(
name='DockerOs',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now_add=True)),
('name', models.CharField(blank=True, max_length=255)),
('version', models.CharField(blank=True, max_length=255)),
('docker_name', models.CharField(blank=True, max_length=255)),
],
options={
'db_table': 'dj_docker_os',
},
),
migrations.CreateModel(
name='Job',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now_add=True)),
('param', models.CharField(blank=True, max_length=255, null=True)),
('datasize', models.IntegerField(blank=True, null=True)),
('version', models.CharField(blank=True, max_length=255, null=True)),
('exec_time', models.IntegerField(blank=True, null=True)),
('access_token', models.CharField(blank=True, max_length=255, null=True)),
('state', models.IntegerField()),
('result', models.IntegerField()),
('container_id', models.IntegerField(blank=True, null=True)),
],
options={
'db_table': 'dj_jobs',
},
),
migrations.CreateModel(
name='JobQueue',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now_add=True)),
('name', models.CharField(max_length=255)),
('timeout', models.IntegerField(blank=True, null=True)),
('is_default', models.IntegerField()),
],
options={
'db_table': 'dj_job_queues',
},
),
migrations.CreateModel(
name='JobUploads',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now_add=True)),
('job_file_file_name', models.CharField(blank=True, max_length=255)),
('job_file_content_type', models.CharField(blank=True, max_length=255)),
('job_file_file_size', models.IntegerField(blank=True, null=True)),
('job_file_updated_at', models.DateTimeField(auto_now_add=True, null=True)),
('dj_job', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='jobuploadjob', to='main.Job')),
],
options={
'db_table': 'dj_job_uploads',
},
),
migrations.CreateModel(
name='Quota',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now_add=True)),
('quantity', models.BigIntegerField(blank=True, null=True)),
('dj_user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quotauser', to=settings.AUTH_USER_MODEL)),
],
options={
'db_table': 'dj_quotas',
},
),
migrations.CreateModel(
name='Webapp',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now_add=True)),
('name', models.CharField(blank=True, max_length=255, unique=True)),
('description', models.TextField(blank=True, null=True)),
('contact', models.CharField(blank=True, max_length=255, null=True)),
('logo_file_name', models.CharField(blank=True, max_length=255, null=True)),
('logo_content_type', models.CharField(blank=True, max_length=255, null=True)),
('logo_file_size', models.IntegerField(blank=True, null=True)),
('logo_updated_at', models.DateTimeField(blank=True, null=True)),
('default_quota', models.IntegerField(blank=True, null=True)),
('docker_name', models.CharField(blank=True, max_length=255)),
('readme', models.IntegerField(blank=True, null=True)),
('entrypoint', models.CharField(blank=True, max_length=255)),
('exec_time', models.IntegerField(blank=True, null=True)),
('private', models.IntegerField(default=1)),
('access_token', models.CharField(blank=True, max_length=255, null=True)),
('sandbox_state', models.IntegerField(null=True)),
('memory_limit', models.BigIntegerField(blank=True, null=True)),
('docker_os', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='webappdockeros', to='main.DockerOs')),
('job_queue', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='webappjobqueue', to='main.JobQueue')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='webappuser', to=settings.AUTH_USER_MODEL)),
],
options={
'db_table': 'dj_webapps',
},
),
migrations.CreateModel(
name='WebappParameter',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now_add=True)),
('value', models.CharField(blank=True, max_length=255, null=True)),
('name', models.CharField(blank=True, max_length=255, null=True)),
('detail', models.CharField(blank=True, max_length=255, null=True)),
('webapp', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='webappparameters', to='main.Webapp')),
],
options={
'db_table': 'dj_webapp_parameters',
},
),
migrations.CreateModel(
name='WebappVersion',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now_add=True)),
('number', models.CharField(blank=True, max_length=255)),
('changelog', models.CharField(blank=True, max_length=255)),
('docker_image_size', models.FloatField(blank=True, null=True)),
('state', models.IntegerField(null=True)),
('published', models.IntegerField()),
('url', models.TextField()),
('webapp', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='webappversion', to='main.Webapp')),
],
options={
'db_table': 'dj_webapp_versions',
},
),
migrations.AddField(
model_name='quota',
name='dj_webapp',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='quotawebapp', to='main.Webapp'),
),
migrations.AddField(
model_name='job',
name='queue',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='queue', to='main.JobQueue'),
),
migrations.AddField(
model_name='job',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='user', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='job',
name='webapp',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='webapp', to='main.Webapp'),
),
]
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-18 07:55
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('main', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Runner',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now_add=True)),
('token', models.CharField(max_length=255, unique=True)),
('hostname', models.CharField(blank=True, max_length=255, null=True)),
('cpu_count', models.IntegerField(blank=True, null=True)),
('mem_in_GB', models.IntegerField(blank=True, null=True)),
('last_seen', models.DateTimeField(null=True)),
('webapps', models.ManyToManyField(related_name='webapps', to='main.Webapp')),
],
options={
'db_table': 'dj_runners',
},
),
migrations.AddField(
model_name='job',
name='runner',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='runner', to='main.Runner'),
),
]
......@@ -163,7 +163,7 @@ class Runner(TimeStampModel):
class Meta:
db_table = 'dj_runners'
#
class Quota(TimeStampModel):
"""
......@@ -203,7 +203,7 @@ class Job(TimeStampModel):
webapp = models.ForeignKey(Webapp, related_name="webapp")
user = models.ForeignKey(User, related_name="user")
#runner = models.OneToOneField(Runner, related_name="runner", blank=True, null=True)
runner = models.OneToOneField(Runner, related_name="runner", blank=True, null=True)
# Not in use because I don't have any related table yet
container_id = models.IntegerField(blank=True, null=True)
......
......@@ -6,9 +6,9 @@ app_name = 'main'
urlpatterns = [
url(r'^$', views.index, name="home"),
url(r'^tokens$', views.tokens, name="tokens"),
# url(r"^runner/cmd/[sha1|sha256|md5]*:(\b[0-9a-f]{5,40}\b)$", views.runner_cmd, name="runner_cmd"),
# url(r"^runner/dw/(.*)", views.runner_dw, name="runner_dw"),
# url(r"^runner/up/(.*)", views.runner_up, name="runner_up"),
url(r"^runner/cmd/[sha1|sha256|md5]*:(\b[0-9a-f]{5,40}\b)$", views.runner_cmd, name="runner_cmd"),
url(r"^runner/dw/(\d+)/(.*)", views.runner_dw, name="runner_dw"),
url(r"^runner/up/(.*)", views.runner_up, name="runner_up"),
url(r'^registryhook', views.registryhook, name="registryhook"),
url(r'^jupyter$', views.jupyter, name="jupyter"),
url(r'^apps/$', views.WebappList.as_view(), name='webapp_list'),
......
......@@ -3,6 +3,7 @@ import json
import logging
import os
import socket
import time
from django.conf import settings
from django.contrib.auth.decorators import login_required
......@@ -10,6 +11,7 @@ from django.contrib.auth.forms import PasswordChangeForm
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.urlresolvers import reverse
from django.http import JsonResponse, HttpResponse
from django.http import StreamingHttpResponse
from django.shortcuts import redirect
from django.shortcuts import render, get_object_or_404
from django.urls import reverse, reverse_lazy
......@@ -21,37 +23,66 @@ from django.views.generic import (
)
from .forms import UserForm, HomeSignupForm
from .models import Webapp, Job, User, AllgoUser, WebappVersion
from .models import User
from .tokens import Token
from .models import Webapp, Job, AllgoUser, WebappVersion, Runner
log = logging.getLogger('allgo')
#
# def runner_dw(request):
# return "FIXME"
#
# def runner_up(request):
# return "FIXME"
#
# def runner_cmd(request):
# auth_header = request.META.get('HTTP_AUTHORIZATION', '')
# if not auth_header:
# log.info("Runner request without http authorisation %s %s %s", request.META['HTTP_USER_AGENT'],
# request.META['REMOTE_ADDR'], request.META['QUERY_STRING'])
# return HttpResponse(status=401)
# token_type, credentials = auth_header.split(' ')
# username, password = base64.b64decode(credentials).decode('utf-8').split(':')
# try:
# user = User.objects.get(email=username)
# except User.DoesNotExist:
# log.warning("Runner request but user doest not exist")
# return HttpResponse(status=401)
# password_valid = user.check_password(password)
# if token_type != 'Basic' or not password_valid:
# log.info("Runner request but user password mismatch")
# return HttpResponse(status=401)
#
# allgouser = AllgoUser(user=user)
# return "FIXME"
def runner_dw(request, jobid, filename):
username, runner = get_token_cred(request)
if username != "$token" or not runner:
log.warning("Runner request $token user or a valid token")
return HttpResponse(status=401)
job = Job.objects.get(runner=runner, id=jobid).first()
if not job:
log.warning("No job found for id %s and runner %s", jobid, runner)
return HttpResponse(status=401)
assert ".." not in filename, "filename unsecure"
datastore = os.environ.get("ALLGO_DATASTORE")
filepath = os.path.join(datastore, jobid, filename)
with open(filepath, 'r') as fp:
data = fp.read()
response = HttpResponse(mimetype="application/octet-stream")
response['Content-Disposition'] = 'attachment; filename=%s' % filename
response.write(data)
return
def runner_up(request):
return "FIXME"
def get_token_cred(request):
auth_header = request.META.get('HTTP_AUTHORIZATION', '')
if not auth_header:
log.info("Runner request without http authorisation %s %s %s", request.META['HTTP_USER_AGENT'],
request.META['REMOTE_ADDR'], request.META['QUERY_STRING'])
return HttpResponse(status=401)
token_type, credentials = auth_header.split(' ')
username, password = base64.b64decode(credentials).decode('utf-8').split(':')
return username, Runner.objects.get(token=password)
def runner_jobs(runner):
while True:
job = Job.objects.filter(state=0, runner=runner).first()
if job:
yield job
time.sleep(5)
def runner_cmd(request):
username, runner = get_token_cred(request)
if username != "$token" or not runner:
log.warning("Runner request $token user or a valid token")
return HttpResponse(status=401)
return StreamingHttpResponse(runner_jobs(runner))
def get_allowed_actions(user, scope, actions):
allgouser = AllgoUser(user=user)
......@@ -116,7 +147,7 @@ def jupyter(request):
token.claim['upn'] = user
encoded_token = token.encode_token()
next = "/user/%s/git-pull?repo=%s" % (user, request.GET.get("repo"))
return redirect(os.environ.get('ALLGO_JUPYTER_URL')+"?bearer=" + encoded_token + "&next=" + next)
return redirect(os.environ.get('ALLGO_JUPYTER_URL') + "?bearer=" + encoded_token + "&next=" + next)
def tokens(request):
......
-- Duplicate all tables before applying any changes
ALTER DATABASE `allgo` CHARACTER SET utf8;
CREATE TABLE auth_user AS SELECT * FROM users;
CREATE TABLE dj_users AS SELECT * FROM users;
CREATE TABLE dj_quotas AS SELECT * FROM quotas;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment