diff options
-rw-r--r-- | docker-compose.yml | 2 | ||||
-rw-r--r-- | src/api/models.py | 37 | ||||
-rw-r--r-- | src/booking/views.py | 4 | ||||
-rw-r--r-- | src/dashboard/tasks.py | 6 | ||||
-rw-r--r-- | src/templates/booking/booking_detail.html | 470 | ||||
-rw-r--r-- | src/templates/booking/booking_table.html | 4 | ||||
-rw-r--r-- | src/templates/booking/steps/booking_meta.html | 3 | ||||
-rw-r--r-- | src/templates/dashboard/multiple_select_filter_widget.html | 1 | ||||
-rw-r--r-- | src/workflow/forms.py | 4 |
9 files changed, 271 insertions, 260 deletions
diff --git a/docker-compose.yml b/docker-compose.yml index eddc54c..f9cf0bb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -40,7 +40,7 @@ services: postgres: restart: always - image: postgres:latest + image: postgres:10 container_name: ps01 env_file: config.env volumes: diff --git a/src/api/models.py b/src/api/models.py index 9a7f775..4237559 100644 --- a/src/api/models.py +++ b/src/api/models.py @@ -333,10 +333,10 @@ class AccessConfig(TaskConfig): def to_dict(self): d = {} - d['access_type'] = self.access_type + d['access_type'] = self.access_type d['user'] = self.user.id d['revoke'] = self.revoke - d['context'] = self.context + d['context'] = json.loads(self.context) return d def get_delta(self): @@ -375,7 +375,7 @@ class AccessConfig(TaskConfig): self.delta = json.dumps(d) def set_context(self, context): - self.context = context + self.context = json.dumps(context) d = json.loads(self.delta) d['context'] = context self.delta = json.dumps(d) @@ -620,18 +620,28 @@ class JobFactory(object): hosts=hosts, job=job ) + all_users = list(booking.collaborators.all()) + all_users.append(booking.owner) cls.makeAccessConfig( - users=booking.collaborators.all(), - access_type="vpn", - revoke=False, - job=job - ) - cls.makeAccessConfig( - users=[booking.owner], + users=all_users, access_type="vpn", revoke=False, job=job ) + for user in all_users: + try: + cls.makeAccessConfig( + users=[user], + access_type="ssh", + revoke=False, + job=job, + context={ + "key": user.userprofile.ssh_public_key.read(), + "hosts": [host.labid for host in hosts] + } + ) + except Exception: + continue @classmethod def makeHardwareConfigs(cls, hosts=[], job=Job()): @@ -658,13 +668,15 @@ class JobFactory(object): hardware_config.save() @classmethod - def makeAccessConfig(cls, users, access_type, revoke=False, job=Job()): + def makeAccessConfig(cls, users, access_type, revoke=False, job=Job(), context=False): for user in users: relation = AccessRelation() relation.job = job config = AccessConfig() config.access_type = access_type config.user = user + if context: + config.set_context(context) config.save() relation.config = config relation.save() @@ -721,6 +733,3 @@ class JobFactory(object): return software_relation except: return None - - def makeAccess(cls, user, access_type, revoke): - pass diff --git a/src/booking/views.py b/src/booking/views.py index 9b9860f..a0ea31d 100644 --- a/src/booking/views.py +++ b/src/booking/views.py @@ -103,6 +103,10 @@ def booking_detail_view(request, booking_id): 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'}) return render(request, "booking/booking_detail.html", { 'title': 'Booking Details', 'booking': booking, diff --git a/src/dashboard/tasks.py b/src/dashboard/tasks.py index c619642..d4b4189 100644 --- a/src/dashboard/tasks.py +++ b/src/dashboard/tasks.py @@ -67,7 +67,11 @@ def booking_poll(): def cleanup_access(qs): for relation in qs: - pass # TODO + if "vpn" in relation.config.access_type.lower(): + relation.config.set_revoke(True) + relation.config.save() + relation.status = JobStatus.NEW + relation.save() cleanup_set = Booking.objects.filter(end__lte=timezone.now()).filter(job__complete=False) diff --git a/src/templates/booking/booking_detail.html b/src/templates/booking/booking_detail.html index 126aaab..cae0e25 100644 --- a/src/templates/booking/booking_detail.html +++ b/src/templates/booking/booking_detail.html @@ -3,289 +3,281 @@ {% block extrahead %} {{block.super}} - <script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js?lang=yaml"></script> +<script src="https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js?lang=yaml"></script> <script src="https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js"></script> {% endblock %} {% block content %} <div class="container-fluid"> <div class="row"> - <div class="col-lg-6"> - <div class="panel panel-default"> - <div class="panel-heading clearfix"> - <h4 style="display: inline;">Overview</h4> - <a data-toggle="collapse" data-target="#panel_overview" class="btn pull-right" style="line-height: 1;" >Expand</a> - </div> - <div class="panel-body" id="panel_overview"> - <table class="table"> - <tr> - <td>Purpose</td> - <td>{{ booking.purpose }}</td> - </tr> - <tr> - <td>Project</td> - <td>{{ booking.project }}</td> - </tr> - <tr> - <td>Start Time</td> - <td>{{ booking.start }}</td> - </tr> - <tr> - <td>End Time</td> - <td>{{ booking.end }}</td> - </tr> - <tr> - <td>Pod Definition</td> - <td>{{ booking.resource.template }}</td> - </tr> - <tr> - <td>Pod Configuration</td> - <td>{{ booking.config_bundle }}</td> - </tr> - <tr> - <td>Lab Deployed At</td> - <td>{{ booking.lab }}</td> - </tr> - </table> - </div> - </div> - <div class="row"> - <div class="col-lg-6"> - <div class="panel panel-default"> - <div class="panel-heading clearfix"> - <h4 style="display: inline;">Pod</h4> - - <a data-toggle="collapse" data-target="#pod_panel" class="btn pull-right" style="line-height: 1;" >Expand</a> + <div class="panel-heading clearfix"> + <h4 style="display: inline;">Overview</h4> + <a data-toggle="collapse" data-target="#panel_overview" class="btn pull-right" style="line-height: 1;" >Expand</a> + </div> + <div class="panel-body" id="panel_overview"> + <table class="table"> + <tr> + <td>Purpose</td> + <td>{{ booking.purpose }}</td> + </tr> + <tr> + <td>Project</td> + <td>{{ booking.project }}</td> + </tr> + <tr> + <td>Start Time</td> + <td>{{ booking.start }}</td> + </tr> + <tr> + <td>End Time</td> + <td>{{ booking.end }}</td> + </tr> + <tr> + <td>Pod Definition</td> + <td>{{ booking.resource.template }}</td> + </tr> + <tr> + <td>Pod Configuration</td> + <td>{{ booking.config_bundle }}</td> + </tr> + <tr> + <td>Lab Deployed At</td> + <td>{{ booking.lab }}</td> + </tr> + </table> + </div> </div> - <div class="panel-body pod_panel" id="pod_panel"> - <table class="table"> - {% for host in booking.resource.hosts.all %} - <tr> - <td><h4>{{host.template.resource.name}}</h4></td> - <td> - <table class="table"> - <tr> - <td>Hostname:</td> - <td>{{host.template.resource.name}}</td> - </tr> - <tr> - <td>Profile:</td> - <td>{{host.name}}</td> - </tr> - <tr> - <td>Role:</td> - <td>{{host.config.opnfvRole}}</td> - </tr> - <tr> - <td>Image:</td> - <td>{{host.config.image}}</td> - </tr> - <tr> - <td>RAM:</td> - <td>{{host.profile.ramprofile.first.amount}}G, - {{host.profile.ramprofile.first.channels}} channels</td> - </tr> + <div class="row"> + + <div class="col-lg-6"> + + <div class="panel panel-default"> + <div class="panel-heading clearfix"> + <h4 style="display: inline;">Pod</h4> + <a data-toggle="collapse" data-target="#pod_panel" class="btn pull-right" style="line-height: 1;" >Expand</a> + </div> + <div class="panel-body pod_panel" id="pod_panel"> + <table class="table"> + {% for host in booking.resource.hosts.all %} <tr> - <td>CPU:</td> + <td><h4>{{host.template.resource.name}}</h4></td> <td> <table class="table"> <tr> - <td>Arch:</td> - <td>{{host.profile.cpuprofile.first.architecture}}</td> + <td>Hostname:</td> + <td>{{host.template.resource.name}}</td> </tr> <tr> - <td>Cores:</td> - <td>{{host.profile.cpuprofile.first.cores}}</td> + <td>Profile:</td> + <td>{{host.name}}</td> </tr> <tr> - <td>Sockets:</td> - <td>{{host.profile.cpuprofile.first.cpus}}</td> + <td>Role:</td> + <td>{{host.config.opnfvRole}}</td> </tr> - </table> - </td> - </tr> - <tr> - <td>DISK:</td> - <td> - <table class="table"> <tr> - <td>Size:</td> - <td>{{host.profile.diskprofile.first.size}}GiB</td> + <td>Image:</td> + <td>{{host.config.image}}</td> </tr> <tr> - <td>Type:</td> - <td>{{host.profile.diskprofile.first.media_type}}</td> + <td>RAM:</td> + <td>{{host.profile.ramprofile.first.amount}}G, + {{host.profile.ramprofile.first.channels}} channels</td> </tr> <tr> - <td>Mount Point:</td> - <td>{{host.profile.diskprofile.first.name}}</td> + <td>CPU:</td> + <td> + <table class="table"> + <tr> + <td>Arch:</td> + <td>{{host.profile.cpuprofile.first.architecture}}</td> + </tr> + <tr> + <td>Cores:</td> + <td>{{host.profile.cpuprofile.first.cores}}</td> + </tr> + <tr> + <td>Sockets:</td> + <td>{{host.profile.cpuprofile.first.cpus}}</td> + </tr> + </table> + </td> </tr> + <tr> + <td>DISK:</td> + <td> + <table class="table"> + <tr> + <td>Size:</td> + <td>{{host.profile.diskprofile.first.size}}GiB</td> + </tr> + <tr> + <td>Type:</td> + <td>{{host.profile.diskprofile.first.media_type}}</td> + </tr> + <tr> + <td>Mount Point:</td> + <td>{{host.profile.diskprofile.first.name}}</td> + </tr> + </table> + </td> + </tr> + <tr> + <td>Interfaces:</td> + <td> + <style> + .borderless td { + border: none !important; + } + </style> + <table class="table"> + {% for intprof in host.profile.interfaceprofile.all %} + <tr> + <td> + <table class="table borderless"> + <tr> + <td>Name:</td> + <td>{{intprof.name}}</td> + </tr> + <tr> + <td>Speed:</td> + <td>{{intprof.speed}}</td> + </tr> + </table> + </td> + </tr> + {% endfor %} + </table> + </td> + </tr> + + </table> + </td> + {% endfor %} </tr> - <tr> - <td>Interfaces:</td> - <td> - <style> - .borderless td { - border: none !important; - } - </style> - <table class="table"> - {% for intprof in host.profile.interfaceprofile.all %} - <tr> - <td> - <table class="table borderless"> - <tr> - <td>Name:</td> - <td>{{intprof.name}}</td> - </tr> - <tr> - <td>Speed:</td> - <td>{{intprof.speed}}</td> - </tr> - </table> - </td> - </tr> - {% endfor %} - </table> - </td> - </tr> + </table> + </div> + </div> + </div> + <div class="col-lg-6"> + <div class="panel panel-default"> + <div class="panel-heading clearfix"> + <h4 style="display: inline;">PDF</h4> + <a data-toggle="collapse" data-target="#pdf_panel" class="btn pull-right" style="line-height: 1;" >Expand</a> + </div> - </table> - - </td> - {% endfor %} - </tr> - </table> + <div class="panel-body" id="pdf_panel" style="padding: 0px;"> + <pre class="prettyprint lang-yaml" style="margin: 0px; padding: 0px; border: none;"> +{{pdf}} + </pre> + </div> + </div> + </div> </div> </div> - </div> <div class="col-lg-6"> + <div class="panel panel-default"> + <div class="panel-heading clearfix"> + <h4 style="display: inline;">Deployment Progress</h4> + <p style="display: inline; margin-left: 10px;"> These are the different tasks that have to be completed before your deployment is ready</p> + <a data-toggle="collapse" data-target="#panel_tasks" class="btn pull-right" style="line-height: 1;" >Expand</a> + </div> - <div class="panel panel-default"> - <div class="panel-heading clearfix"> - <h4 style="display: inline;">PDF</h4> - <a data-toggle="collapse" data-target="#pdf_panel" class="btn pull-right" style="line-height: 1;" >Expand</a> - </div> - - <div class="panel-body" id="pdf_panel" style="padding: 0px;"> - <pre class="prettyprint lang-yaml" style="margin: 0px; padding: 0px; border: none;"> - - {{pdf}} - - - </pre> - </div> - </div> - </div> - </div> - </div> - - + <div class="panel-body" id="panel_tasks"> + <table class="table"> + <style> + .progress { + display: inline-block; + border: 3px solid #f3f3f3; + border-radius: 50%; + border-top: 3px solid #12aebb; + width: 20px; + height: 20px; + -webkit-animation: spin 2s linear infinite; /* Safari */ + animation: spin 2s linear infinite; + } - <div class="col-lg-6"> - <div class="panel panel-default"> - <div class="panel-heading clearfix"> - <h4 style="display: inline;">Deployment Progress</h4> - <p style="display: inline; margin-left: 10px;"> These are the different tasks that have to be completed before your deployment is ready</p> - <a data-toggle="collapse" data-target="#panel_tasks" class="btn pull-right" style="line-height: 1;" >Expand</a> - </div> + @keyframes spin { + 0% {transform: rotate(0deg);} + 100% {transform: rotate(360deg);} + } - <div class="panel-body" id="panel_tasks"> - <table class="table"> - <style> - .progress { - display: inline-block; - border: 3px solid #f3f3f3; - border-radius: 50%; - border-top: 3px solid #12aebb; - width: 20px; - height: 20px; - -webkit-animation: spin 2s linear infinite; /* Safari */ - animation: spin 2s linear infinite; - } + .new { + display: inline-block; + width: 20px; + height: 20px; + background: #f3f3f3; + border-radius: 50%; + animation: fadeInOut 1s infinite alternate; - @keyframes spin { - 0% {transform: rotate(0deg);} - 100% {transform: rotate(360deg);} - } - .new { - display: inline-block; - width: 20px; - height: 20px; - background: #f3f3f3; - border-radius: 50%; - animation: fadeInOut 1s infinite alternate; + } + @keyframes fadeInOut { + from { opacity: 0;} + } + .done { + display: inline-block; + width: 20px; + height: 20px; + background: #40B976; + border-radius: 50%; + } + </style> + <tr> + <th></th> + <th>Status</th> + <th>Lab Response</th> + <th>Type</th> + </tr> + {% for task in booking.job.get_tasklist %} + <tr> + <td> + {% if task.status < 100 %} + <div class="new"></div> + {% elif task.status < 200 %} + <div class="progress"></div> + {% else %} + <div class="done"></div> + {% endif %} + </td> - } - @keyframes fadeInOut { - from { opacity: 0;} - } - .done { - display: inline-block; - width: 20px; - height: 20px; - background: #40B976; - border-radius: 50%; - } - </style> - <tr> - <th></th> - <th>Status</th> - <th>Lab Response</th> - <th>Type</th> - </tr> - {% for task in booking.job.get_tasklist %} - <tr> - <td> - {% if task.status < 100 %} - <div class="new"></div> - {% elif task.status < 200 %} - <div class="progress"></div> - {% else %} - <div class="done"></div> - {% endif %} + <td> + {% if task.status < 100 %} + PENDING + {% elif task.status < 200 %} + IN PROGRESS + {% else %} + DONE + {% endif %} </td> + <td> + {% if task.message %} + {% if task.type_str == "Access Task" and user_id != task.config.user.id %} + Message from Lab: <pre>--secret--</pre> + {% else %} + Message from Lab: <pre>{{ task.message }}</pre> + {% endif %} + {% else %} + No response provided (yet) + {% endif %} + </td> + <td> + {{ task.type_str }} - <td> - {% if task.status < 100 %} - PENDING - {% elif task.status < 200 %} - IN PROGRESS - {% else %} - DONE - {% endif %} - </td> - <td> - - {% if task.message %} - {% if task.type_str == "Access Task" and user_id != task.config.user.id %} - Message from Lab: <pre>--secret--</pre> - {% else %} - Message from Lab: <pre>{{ task.message }}</pre> - {% endif %} - {% else %} - No response provided (yet) - {% endif %} - </td> - <td> - {{ task.type_str }} - - </td> - </tr> - {% endfor %} - </table> + </td> + </tr> + {% endfor %} + </table> + </div> </div> </div> - - </div> </div> </div> diff --git a/src/templates/booking/booking_table.html b/src/templates/booking/booking_table.html index af2248c..5e82645 100644 --- a/src/templates/booking/booking_table.html +++ b/src/templates/booking/booking_table.html @@ -3,7 +3,7 @@ <thead> <tr> - <th>User</th> + <th>Owner</th> <th>Purpose</th> <th>Start</th> <th>End</th> @@ -16,7 +16,7 @@ {% for booking in bookings %} <tr> <td> - {{ booking.user.username }} + {{ booking.owner.username }} </td> <td> {{ booking.purpose }} diff --git a/src/templates/booking/steps/booking_meta.html b/src/templates/booking/steps/booking_meta.html index fa8f7a9..a42e158 100644 --- a/src/templates/booking/steps/booking_meta.html +++ b/src/templates/booking/steps/booking_meta.html @@ -43,7 +43,8 @@ <div class="panel panel_center"> </div> <div class="panel"> - {% bootstrap_field form.users %} + <p>You may add collaborators on your booking to share resources with coworkers.</p> + {% bootstrap_field form.users label="Collaborators" %} </div> {% buttons %} diff --git a/src/templates/dashboard/multiple_select_filter_widget.html b/src/templates/dashboard/multiple_select_filter_widget.html index ed29ed6..31b8f33 100644 --- a/src/templates/dashboard/multiple_select_filter_widget.html +++ b/src/templates/dashboard/multiple_select_filter_widget.html @@ -337,6 +337,7 @@ function add_item_prepopulate(node, prepopulate){ button.appendChild(document.createTextNode("Remove")); div.appendChild(button); document.getElementById("dropdown_wrapper").appendChild(div); + updateObjectResult(div); return div; } diff --git a/src/workflow/forms.py b/src/workflow/forms.py index c770e38..d4abbc3 100644 --- a/src/workflow/forms.py +++ b/src/workflow/forms.py @@ -189,6 +189,7 @@ class BookingMetaForm(forms.Form): default_user = kwargs.pop("default_user") else: default_user = "you" + self.default_user = default_user if "chosen_users" in kwargs: chosen_users = kwargs.pop("chosen_users") elif data and "users" in data: @@ -212,7 +213,7 @@ class BookingMetaForm(forms.Form): """ try: users = {} - d_qset = UserProfile.objects.select_related('user').all(); + d_qset = UserProfile.objects.select_related('user').all().exclude(user__username=self.default_user); for userprofile in d_qset: user = { 'id':userprofile.user.id, @@ -237,7 +238,6 @@ class BookingMetaForm(forms.Form): 'selectable_limit': -1, 'name': "users", 'placeholder': "username", - 'default_entry': default_user, 'initial': chosen_users, 'edit': False } |