Skip to content

Commit

Permalink
Add deployment overview page (#37)
Browse files Browse the repository at this point in the history
* Add route for deployment overview page

* Add dropdown menu for Deployments in nav bar

* Add dep overview template

* Add functions for color array generation

* Import randomcolor lib

* Fix deployments overview results
  • Loading branch information
maricaantonacci authored Apr 18, 2022
1 parent ea15108 commit 8a064a2
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 5 deletions.
70 changes: 69 additions & 1 deletion app/deployments/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,15 @@
if not issuer.endswith('/'):
issuer += '/'

@deployments_bp.route('/depls')
@auth.authorized_with_valid_token
def showdeploymentsingroup():
group = request.args['group']
session['active_usergroup'] = group
flash("Project set to {}".format(group), 'info')
return redirect(url_for('deployments_bp.showdeployments'))

@deployments_bp.route('/all')
@deployments_bp.route('/list')
@auth.authorized_with_valid_token
def showdeployments():
access_token = iam_blueprint.session.token['access_token']
Expand Down Expand Up @@ -79,6 +86,67 @@ def showdeployments():
return render_template('deployments.html', deployments=deployments)


def update_deployments():
issuer = settings.iamUrl
if not issuer.endswith('/'):
issuer += '/'

subject = session['userid']

# retrieve deployments from orchestrator
access_token = iam_blueprint.session.token['access_token']

headers = {'Authorization': 'bearer %s' % access_token}

url = settings.orchestratorUrl + "/deployments?createdBy={}&page={}&size={}".format(
'{}@{}'.format(subject, issuer), 0, 999999)
response = requests.get(url, headers=headers)

iids = []
if response.ok:
deporch = response.json()["content"]
iids = dbhelpers.updatedeploymentsstatus(deporch, subject)['iids']

#
# retrieve deployments from DB
deployments = dbhelpers.cvdeployments(dbhelpers.get_user_deployments(subject))
for dep in deployments:
newremote = dep.remote
if dep.uuid not in iids:
if dep.remote == 1:
newremote = 0
else:
if dep.remote == 0:
newremote = 1
if dep.remote != newremote:
dbhelpers.update_deployment(dep.uuid, dict(remote=newremote))

@deployments_bp.route('/overview')
@auth.authorized_with_valid_token
def showdeploymentsoverview():

# refresh deployment list
update_deployments();

deps = dbhelpers.get_user_deployments(session["userid"])
statuses = {}
projects = {}
providers = {}
for dep in deps:
status = dep.status if dep.status else "UNKNOWN"
if status != 'DELETE_COMPLETE' and dep.remote == 1:
statuses[status] = 1 if status not in statuses else statuses[status] + 1
project = dep.user_group if dep.user_group else "UNKNOWN"
projects[project] = 1 if project not in projects else projects[project] + 1
provider = dep.provider_name if dep.provider_name else "UNKNOWN"
providers[provider] = 1 if provider not in providers else providers[provider] + 1

return render_template('depoverview.html',
s_title="Deployments status", s_labels=list(statuses.keys()), s_values=list(statuses.values()), s_colors=utils.genstatuscolors(statuses),
p_title="Projects", p_labels=list(projects.keys()), p_values=list(projects.values()), p_colors=utils.gencolors("blue", len(projects)),
pr_title="Providers", pr_labels=list(providers.keys()), pr_values=list(providers.values()), pr_colors=utils.gencolors("green", len(providers)))


@deployments_bp.route('/<depid>/template')
@auth.authorized_with_valid_token
def deptemplate(depid=None):
Expand Down
100 changes: 100 additions & 0 deletions app/deployments/templates/depoverview.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
{% extends "base.html" %}
{% block content %}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.min.js"></script>

<div class="container-fluid">
{% set ar = namespace(found=false) %}
<br>
<div class="card shadow mb-4">
<div class="card-header py-3">
<div class="row">
<div class="col-md-6">
<!-- Title -->
<h4 class="font-weight-bold text-primary">Deployments Overview</h4>
</div>
<div class="col-md-6 text-right">
<!-- Button -->
<button type=button class='btn btn-outline-secondary' onclick='location.href="{{ url_for('deployments_bp.showdeploymentsoverview') }}"'><span class='fas fa-sync mr-2'></span>Refresh</button>

<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown"><span class='fas fa-list mr-2'></span>Details </button>
<div class="dropdown-menu">
{% for group in session['supported_usergroups'] %}
<a class="dropdown-item" href="{{ url_for('deployments_bp.showdeploymentsingroup', group=group) }}">{{group}}</a>
{% endfor %}
</div>
</div>
</div>
</div>
<div class="card-body">
<div class="row">
<div class="col">
<canvas id="status_chart" width="300" height="500" style="max-width:300px;max-height:500px"></canvas>
</div>
<div class="col">
<canvas id="projects_chart" width="300" height="500" style="max-width:300px;max-height:500px"></canvas>
</div>
<div class="col">
<canvas id="providers_chart" width="300" height="500" style="max-width:300px;max-height:500px"></canvas>
</div>
</div>
</div>
</div>
</div>

<script>

function drawchart(chartid, title, subtitle, labels, values, colors) {
var ctx = document.getElementById(chartid).getContext("2d");
var chart = new Chart(ctx, {
type: 'pie',
data: {
labels: labels,
datasets: [{
data: values,
backgroundColor: colors,
borderWidth: 1
}]
},

// Configuration options go here
options: {
responsive: true,
plugins: {
title: {
display: true,
text: title ,
font: {
size: 18
},
color: "#111",
padding : {
bottom: 10
}
},
subtitle: {
display: true,
text: subtitle,
color: 'grey'
},
legend: {
position: "bottom",
align: "start"
}
}
}
});

}
console.log("{{s_text}}");
drawchart("status_chart", "{{s_title}}", "", {{ s_labels | safe}}, {{ s_values }}, {{s_colors | safe}});
drawchart("projects_chart", "{{p_title}}", "deployments distribution per project", {{ p_labels | safe}}, {{ p_values }}, {{p_colors | safe}});
drawchart("providers_chart", "{{pr_title}}", "deployments distribution per provider", {{ pr_labels | safe}}, {{ pr_values }}, {{pr_colors | safe}});
</script>



{% if ar.found %}
<script>setTimeout(function(){location.reload();},30000);</script>
{% endif %}
{% endblock %}

10 changes: 8 additions & 2 deletions app/home/templates/base.html
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,13 @@
<div class="collapse navbar-collapse" id="myNavbar">
<ul class="navbar-nav mr-auto">
{% if session['username'] %}
<li class="nav-item active"><a class="nav-link" href="{{ url_for("deployments_bp.showdeployments") }}">Deployments</a></li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#">Deployments</a>
<div class="dropdown-menu">
<a class="dropdown-item" href="{{ url_for("deployments_bp.showdeploymentsoverview") }}">Overview</a>
<a class="dropdown-item" href="{{ url_for("deployments_bp.showdeployments") }}">List</a>
</div>
</li>
{% if enable_advanced_menu == "yes" or session['userrole'] == 'admin' %}
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#">Advanced</a>
Expand Down Expand Up @@ -124,7 +130,7 @@
</ul>
{% if session['username'] %}
<ul class="navbar-nav ml-auto">
{% if session['active_usergroup'] != None and 'gets3creds' not in request.path %}
{% if session['active_usergroup'] != None and 'gets3creds' not in request.path and 'overview' not in request.path %}
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#">
{{ session['active_usergroup'] }}<span class="caret"></span>
Expand Down
26 changes: 26 additions & 0 deletions app/lib/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import requests
import linecache
import sys
import randomcolor
import re
import string
import secrets
Expand All @@ -32,6 +33,31 @@ def to_pretty_json(value):
indent=4, separators=(',', ': '))



def gencolors(hue, n):
rand_color = randomcolor.RandomColor(42)
rcolors = rand_color.generate(hue=hue, luminosity="dark", count=n)
return rcolors


def genstatuscolors(statuses):
colors = []
for status in statuses:
if status == "CREATE_COMPLETE":
colors.append('green')
elif status == "CREATE_IN_PROGRESS":
colors.append("lightgreen")
elif status == "DELETE_IN_PROGRESS":
colors.append('salmon')
elif status == "CREATE_FAILED":
colors.append('red')
elif status == "DELETE_FAILED":
colors.append('firebrick')
else:
colors.append('lightgrey')
return colors


def intersect(a, b):
return set(a).intersection(b)

Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ Flask-Migrate==3.1.0
Flask-Alembic==2.0.1
alembic==1.7.7
Flask-Script==2.0.6
visitor==0.1.3
tzlocal==4.1
PyMySQL==1.0.2
python-swiftclient==3.13.1
Expand All @@ -23,4 +22,5 @@ pycryptodomex==3.14.1
hvac==0.11.2
MarkupSafe==2.1.1
boto3==1.21.27
python-ldap==3.4.0
python-ldap==3.4.0
randomcolor

0 comments on commit 8a064a2

Please sign in to comment.