Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Lessee Offer View #3

Merged
merged 1 commit into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 63 additions & 18 deletions esi_ui/api/esi_api.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import json
import dateutil
import pytz
import concurrent.futures

from django.conf import settings
Expand Down Expand Up @@ -45,31 +48,35 @@ def node_list_full_info(connection):
with concurrent.futures.ThreadPoolExecutor() as executor:
f1 = executor.submit(connection.lease.nodes)
f2 = executor.submit(connection.baremetal.nodes, details=True)
f3 = executor.submit(connection.lease.leases)
esi_nodes = list(f1.result())
baremetal_nodes = list(f2.result())
leases = list(f3.result())

list_of_nodes = []
for e in esi_nodes:
list_of_nodes.append((e, next((bm for bm in baremetal_nodes if e.id == bm.id), None)))
for lease in leases:
list_of_nodes.append((lease, next((e for e in esi_nodes if e.id == lease.resource_uuid), None),
next((bm for bm in baremetal_nodes if bm.id == lease.resource_uuid), None)))

return [
{
'uuid': e.id,
'name': e.name,
'maintenance': e.maintenance,
'provision_state': e.provision_state,
'target_provision_state': bm.target_provision_state,
'power_state': bm.power_state,
'target_power_state': bm.target_power_state,
'properties': e.properties,
'lease_uuid': e.lease_uuid,
'owner': e.owner,
'lessee': e.lessee,
'resource_class': e.resource_class,
'future_offers': e.future_offers,
'future_leases': e.future_leases,
'uuid': lease.resource_uuid,
'name': lease.resource,
'maintenance': e.maintenance if lease.status == 'active' else '',
'provision_state': e.provision_state if lease.status == 'active' else '',
'target_provision_state': bm.target_provision_state if lease.status == 'active' else '',
'power_state': bm.power_state if lease.status == 'active' else '',
'target_power_state': bm.target_power_state if lease.status == 'active' else '',
'properties': [[key, value] for key, value in lease.resource_properties.items()],
'lease_uuid': lease.id,
'owner': lease.owner,
'lessee': e.lessee if lease.status == 'active' else '',
'resource_class': lease.resource_class,
'start_time': lease.start_time.replace('T', ' ', 1),
'end_time': lease.end_time.replace('T', ' ', 1),
'status': lease.status
}
for e, bm in list_of_nodes if bm is not None
for lease, e, bm in list_of_nodes
]

with concurrent.futures.ThreadPoolExecutor() as executor:
Expand All @@ -91,7 +98,7 @@ def node_list_full_info(connection):
node['fixed_ips'] = []
node['floating_networks'] = []
node['floating_ips'] = []
if network_info:
if node['status'] == 'active' and network_info:
for info in network_info:
node['mac_addresses'].append(info['baremetal_port'].address)
node['network_port_names'].append(info['network_ports'][0].name
Expand Down Expand Up @@ -125,3 +132,41 @@ def set_power_state(request, node, target):
target = target.split(' ', 1)[1]

return esiclient(token=token).baremetal.wait_for_node_power_state(node=node, expected_state=target)


def offer_list(request):
token = request.user.token.id

offers = esiclient(token=token).list_offers()

return [
{
'resource': offer.resource,
'resource_class': offer.resource_class,
'status': offer.status,
'start_time': offer.start_time.replace('T', ' ', 1),
'end_time': offer.end_time.replace('T', ' ', 1),
'uuid': offer.uuid,
'availabilities': [[avail[0].replace('T', ' ', 1), avail[1].replace('T', ' ', 1)] for avail in offer.availabilities],
'resource_properties': [[key, value] for key, value in offer.resource_properties.items()],
}
for offer in offers
]


def offer_claim(request, offer):
token = request.user.token.id
times = json.loads(request.body.decode('utf-8'))

if times['start_time'] is None:
del times['start_time']
if times['end_time'] is None:
del times['end_time']

return esiclient(token=token).claim_offer(offer, **times)


def delete_lease(request, lease):
token = request.user.token.id

return esiclient(token=token).lease.delete_lease(lease)
32 changes: 32 additions & 0 deletions esi_ui/api/esi_rest_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,35 @@ def put(self, request, node):
target = request.DATA.get('target')
return esi_api.set_power_state(request, node, target)


@urls.register
class Offers(generic.View):

url_regex = r'esi/offers/$'

@rest_utils.ajax()
def get(self, request):
offers = esi_api.offer_list(request)
return {
'offers': offers
}


@urls.register
class Offer(generic.View):

url_regex = r'esi/offers/(?P<offer>{})$'.format(LOGICAL_NAME_PATTERN)

@rest_utils.ajax(data_required=True)
def put(self, request, offer):
return esi_api.offer_claim(request, offer)


@urls.register
class Lease(generic.View):

url_regex = r'esi/lease/(?P<lease>{})$'.format(LOGICAL_NAME_PATTERN)

@rest_utils.ajax()
def delete(self, request, lease):
return esi_api.delete_lease(request, lease)
Empty file.
7 changes: 7 additions & 0 deletions esi_ui/content/offers/panel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from django.utils.translation import gettext_lazy as _
import horizon


class Offers(horizon.Panel):
name = _("Offers")
slug = "offers"
22 changes: 22 additions & 0 deletions esi_ui/content/offers/templates/offers/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{% extends 'base.html' %}
{% load i18n %}
{% block title %}{% trans "ESI Lessee" %}{% endblock %}

{% block breadcrumb_nav %}
<ol class="breadcrumb">
<li>{% trans "Project" %}</li>
<li>{% trans "ESI" %}</li>
<li>{% trans "Offers" %}</li>
</ol>
{% endblock %}

{% block page_header %}
<hz-page-header
header="{$ 'Offer Info' | translate $}">
</hz-page-header>
{% endblock page_header %}

{% block main %}
<ng-include src="'{{ STATIC_URL }}dashboard/project/esi/offers.html'">
</ng-include>
{% endblock %}
8 changes: 8 additions & 0 deletions esi_ui/content/offers/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from django.urls import re_path

import esi_ui.api.esi_rest_api
from esi_ui.content.offers import views

urlpatterns = [
re_path(r'^$', views.IndexView.as_view(), name='index'),
]
5 changes: 5 additions & 0 deletions esi_ui/content/offers/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from django.views import generic


class IndexView(generic.TemplateView):
template_name = 'project/offers/index.html'
27 changes: 27 additions & 0 deletions esi_ui/enabled/_6020_project_offers_panel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# The name of the panel to be added to HORIZON_CONFIG. Required.
PANEL = 'offers'

# The name of the dashboard the PANEL associated with. Required.
PANEL_DASHBOARD = 'project'
PANEL_GROUP = 'esi'

# Python panel class of the PANEL to be added.
ADD_PANEL = 'esi_ui.content.offers.panel.Offers'

# A list of applications to be prepended to INSTALLED_APPS
#ADD_INSTALLED_APPS = ['esi_ui']

# A list of AngularJS modules to be loaded when Angular bootstraps.
#ADD_ANGULAR_MODULES = ['horizon.dashboard.project.esi']

# Automatically discover static resources in installed apps
AUTO_DISCOVER_STATIC_FILES = True

# A list of js files to be included in the compressed set of files
#ADD_JS_FILES = []

# A list of scss files to be included in the compressed set of files
#ADD_SCSS_FILES = ['dashboard/identity/myplugin/mypanel/mypanel.scss']

# A list of template-based views to be added to the header
#ADD_HEADER_SECTIONS = ['esi_ui.content.esi_nodes.views.HeaderView',]
22 changes: 15 additions & 7 deletions esi_ui/static/dashboard/project/esi/esi.module.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,22 @@
$provide.constant('horizon.dashboard.project.esi.nodeConfig', {
selectAll: true,
expand: true,
trackId: 'uuid',
trackId: 'lease_uuid',
columns: [
{id: 'name', title: 'Name', priority: 1, sortDefault: true},
{id: 'provision_state', title: 'Provision State', priority: 1},
{id: 'power_state', title: 'Power State', priority: 1},
{id: 'maintenance', title: 'Maintenance', priority: 1},
{id: 'uuid', title: 'UUID', priority: 1},
{id: 'status', title: 'Status', priority: 1},
],
lease_details: [
{id: 'lessee', title: 'Lessee', priority: 1},
{id: 'owner', title: 'Owner', priority: 1},
{id: 'resource_class', title: 'Resource Class', priority: 1},
{id: 'start_time', title: 'Start Time', priority: 1},
{id: 'end_time', title: 'End Time', priority: 1},
{id: 'lease_uuid', title: 'Lease UUID', priority: 1},
{id: 'properties', title: 'Properties', priority: 1},
],
network_details: [
{id: 'mac_addresses', title: 'MAC Address', priority: 1},
Expand All @@ -44,13 +47,13 @@
columns: [
{id: 'resource', title: 'Resource', priority: 1, sortDefault: true},
{id: 'resource_class', title: 'Resource Class', priority: 1},
{id: 'project', title: 'Project', priority: 1},
{id: 'start_time', title: 'Start Time', priority: 1},
{id: 'end_time', title: 'End Time', priority: 1},
{id: 'uuid', title: 'UUID', priority: 1},
{id: 'status', title: 'Status', priority: 1},
{id: 'start_time', title: 'Start Time (UTC)', priority: 1},
{id: 'end_time', title: 'End Time (UTC)', priority: 1},
{id: 'availabilities', title: 'Availabilities (UTC)', priority: 1},
],
offer_details: [
{id: 'availabilities', title: 'Availabilities', priority: 1},
{id: 'uuid', title: 'UUID', priority: 1},
{id: 'resource_properties', title: 'Resource Properties', priority: 1},
]
});
Expand Down Expand Up @@ -101,6 +104,11 @@
name: 'lease_uuid',
singleton: true
},
{
label: gettext('Properties'),
name: 'properties',
singleton: true
},
{
label: gettext('MAC Address'),
name: 'mac_addresses',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
(function () {
'use strict';

angular
.module('horizon.dashboard.project.esi')
.controller('horizon.dashboard.project.esi.OfferModalFormController', controller);

controller.$inject = [
'$uibModalInstance'
];

function controller($uibModalInstance) {
var ctrl = this;

ctrl.formTitle = 'Claim Offers';
ctrl.submitText = 'Submit';
ctrl.start_date = null;
ctrl.start_time = null;
ctrl.end_date = null;
ctrl.end_time = null;

ctrl.submit = submit;

////////////////

function submit($event) {
$event.preventDefault();
$event.stopPropagation();

var start = null;
var end = null;

if (ctrl.start_date !== null) {
start = new Date();
start.setUTCFullYear(ctrl.start_date.getUTCFullYear());
start.setUTCMonth(ctrl.start_date.getUTCMonth());
start.setUTCDate(ctrl.start_date.getUTCDate());
start.setUTCHours(ctrl.start_time.getHours());
start.setUTCMinutes(ctrl.start_time.getMinutes());
start.setUTCSeconds(0);
start.setUTCMilliseconds(0);
}
if (ctrl.end_date !== null) {
end = new Date();
end.setUTCFullYear(ctrl.end_date.getUTCFullYear());
end.setUTCMonth(ctrl.end_date.getUTCMonth());
end.setUTCDate(ctrl.end_date.getUTCDate());
end.setUTCHours(ctrl.end_time.getHours());
end.setUTCMinutes(ctrl.end_time.getMinutes());
end.setUTCSeconds(0);
end.setUTCMilliseconds(0);
}

return $uibModalInstance.close({
start_time: start,
end_time: end
});
}
}

})();
42 changes: 42 additions & 0 deletions esi_ui/static/dashboard/project/esi/forms/offer-modal-form.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<div class="modal-header">
<a class="close" ng-click="$dismiss()">
<span class="fa fa-times"></span>
</a>
<div class="h4 modal-title">
{$::ctrl.formTitle$}
</div>
</div>

<form name="schemaForm">
<div class="modal-body" style="display: flex">
<div style="width: 50%; text-align: center">
<label for="start">{$ ::'Start Time (UTC)' | translate $}</label>
<br>
<input type="date" id="start" ng-model="ctrl.start_date" />
<input type="time" id="start" ng-required="ctrl.start_date" ng-model="ctrl.start_time" />
<span>{$ ::'Default: now' | translate $}</span>
</div>
<div style="width: 50%; text-align: center">
<label for="end">{$ ::'End Time (UTC)' | translate $}</label>
<br>
<input type="date" id="end" ng-model="ctrl.end_date" />
<input type="time" id="end" ng-required="ctrl.end_date" ng-model="ctrl.end_time" />
<span>{$ ::'Default: offer end time' | translate $}</span>
</div>
</div>
</form>

<div class="modal-footer">
<button type="button" class="btn btn-default pull-left" ng-click="$dismiss()">
<span class="fa fa-close"></span>
<translate>Cancel</translate>
</button>

<button type="button"
class="btn btn-primary"
ng-disabled="schemaForm.$invalid"
ng-click="ctrl.submit($event)">
<span class="fa fa-chevron-right"></span>
{$::ctrl.submitText$}
</button>
</div>
Loading