Skip to content

Commit d73159b

Browse files
committed
feat: added processors to available web
closes: #573 Change-Id: I7b284be7c28f82318a8268ccd04246eacb09699f
1 parent 01abe23 commit d73159b

File tree

6 files changed

+55
-16
lines changed

6 files changed

+55
-16
lines changed

conf/quads.yml

-12
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
spare_pool_name: cloud01
88
spare_pool_description: "Spare Pool"
99
spare_pool_owner: quads
10-
# Define the name of the QUADS environment
11-
lab_name: "Lab"
1210
# display name for QUADS email notifications
1311
mail_display_name: "QUADS Scheduler"
1412
# set header for User-Agent:
@@ -45,11 +43,6 @@ ircbot_channel: #yourchannel
4543
webhook_notify: false
4644
webhook_url: https://chat.example.com/v1/spaces/AAABBBCCC
4745

48-
# (optional ticket system URL) in this case we're using JIRA
49-
ticket_url: https://issues.example.com/browse
50-
# (optional ticket queue name) this is typically the ticket queue
51-
# name or abbreviation in the case of JIRA
52-
ticket_queue: SCALELAB
5346
# Jira Specific Variables
5447
jira_url: https://issues.example.com/rest/api/2
5548

@@ -103,14 +96,9 @@ exclude_hosts: cyclades|s4810|z9000|5548|foreman|c08-h30-r630|c08-h05-r930|b08-|
10396
# e.g. c01-h23-r620 is an r620 type host in rack c01 at u-location 23
10497
racks: b09 b10 c01 c02 c03 c04 c05 c06 c07 c08 c09 c10
10598

106-
# visual web dir is where the visual HTML representation of the lab usage goes
107-
visual_web_dir: /opt/quads/web/visual
10899
# this is where we place the generated instackenv.json files
109100
# directory needs to be readable by the nginx user
110101
json_web_path: /opt/quads/web/instack
111-
# path to the user specific web content for quads-web
112-
web_content_path: /opt/quads/web
113-
web_exclude_dirs: .git static instack visual
114102
# number of days of retaining old .json files
115103
json_retention_days: 0
116104

conf/quadsweb.yml

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# path to the user specific web content for quads-web
2+
web_content_path: /opt/quads/web
3+
web_exclude_dirs: .git static instack visual
4+
5+
# visual web dir is where the visual HTML representation of the lab usage goes
6+
visual_web_dir: /opt/quads/web/visual
7+
8+
# (optional ticket system URL) in this case we're using JIRA
9+
ticket_url: https://issues.example.com/browse
10+
# (optional ticket queue name) this is typically the ticket queue
11+
# name or abbreviation in the case of JIRA
12+
ticket_queue: SCALELAB
13+
14+
# Define the name of the QUADS environment
15+
lab_name: "Lab"
16+
17+
# Flag to show GPU information in the web interface
18+
show_gpu: true

rpm/quads.spec

+1
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ rm -rf %{buildroot}
141141
/opt/quads/conf/quads.cron.example
142142
/usr/bin/quads
143143
%config(noreplace) /opt/quads/conf/quads.yml
144+
%config(noreplace) /opt/quads/conf/quadsweb.yml
144145
%config(noreplace) /opt/quads/conf/selfservice.yml
145146
%config(noreplace) /opt/quads/conf/vlans.yml
146147
%config(noreplace) /opt/quads/conf/hosts_metadata.yml

src/quads/config.py

+3
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@
77
logger = logging.getLogger(__name__)
88

99
DEFAULT_CONF_PATH = "/opt/quads/conf/quads.yml"
10+
WEB_CONF_PATH = "/opt/quads/conf/quadsweb.yml"
1011
SS_CONF_PATH = "/opt/quads/conf/selfservice.yml"
1112

1213

1314
class _ConfigBase:
1415
def __init__(self):
1516
self.loaded = False
1617
self.load_from_yaml(DEFAULT_CONF_PATH)
18+
self.load_from_yaml(WEB_CONF_PATH)
1719
self.load_from_yaml(SS_CONF_PATH)
1820

1921
def load_from_yaml(self, filepath: str = DEFAULT_CONF_PATH):
@@ -132,4 +134,5 @@ def API_URL(self):
132134
if __name__ == "__main__":
133135
if not Config.loaded:
134136
Config.load_from_yaml(DEFAULT_CONF_PATH)
137+
Config.load_from_yaml(WEB_CONF_PATH)
135138
Config.load_from_yaml(SS_CONF_PATH)

src/quads/web/blueprints/wiki.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,12 @@ async def broken():
8585

8686
@wiki_bp.route("/available", methods=["GET", "POST"])
8787
async def available():
88+
show_gpu = Config.get("show_gpu")
8889
search = ModelSearchForm(request.form)
8990
if request.method == "POST":
9091
return await search_results(search)
9192

92-
return render_template("wiki/available.html", form=search, available_hosts=[])
93+
return render_template("wiki/available.html", form=search, available_hosts=[], show_gpu=show_gpu)
9394

9495

9596
@wiki_bp.route("/results")

src/quads/web/templates/wiki/available.html

+31-3
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ <h2>QUADS Available Hosts</h2>
5656
<th scope="col">Hostname</th>
5757
<th scope="col">Cloud</th>
5858
<th scope="col">Model</th>
59+
{% if show_gpu %}
60+
<th scope="col">GPU</th>
61+
{% endif %}
5962
<th scope="col">Disks</th>
6063
</tr>
6164
</thead>
@@ -70,6 +73,14 @@ <h2>QUADS Available Hosts</h2>
7073
<td>{{ host["name"] }}</td>
7174
<td>{{ host["cloud"] }}</td>
7275
<td>{{ host["model"] }}</td>
76+
{% if show_gpu %}
77+
{% if host.processors and host.processors|selectattr("processor_type", "equalto", "GPU")|list %}
78+
<td data-bs-toggle="modal"
79+
data-bs-target="#baseModal" onclick="updateProcessors({{ host.processors }})">&#129504;</td>
80+
{% else %}
81+
<td>&#10060;</td>
82+
{% endif %}
83+
{% endif %}
7384
{% if host.disks %}
7485
<td data-bs-toggle="modal"
7586
data-bs-target="#baseModal" onclick="updateDisks({{ host.disks }})">&#128190;</td>
@@ -93,15 +104,32 @@ <h2>QUADS Available Hosts</h2>
93104
<script>
94105
const updateDisks = (disks) => {
95106
document.getElementsByClassName('modal-title')[0].innerHTML = 'Disks'
107+
let th_data = "<tr><th>Type</th><th>Size</th><th>Count</th></tr>"
96108
let td_data = ""
97109
disks.forEach(disk => {
98-
td_data += `<tr><td>${disk["disk_type"]}</td>`
110+
td_data += `<tr>`
111+
td_data += `<td>${disk["disk_type"]}</td>`
99112
td_data += `<td>${disk["disk_size"]}</td>`
100-
td_data += `<td>${disk["disk_count"]}</td></tr>`
113+
td_data += `<td>${disk["disk_count"]}</td>`
114+
td_data += `</tr>`
101115
})
102-
let th_data = "<tr><th>DiskType</th><th>DiskSize</th><th>DiskCount</th></tr>"
103116
document.getElementsByClassName('modal-body')[0].innerHTML = `<table class="table">${th_data}${td_data}</table>`;
104117
};
118+
const updateProcessors = (processors) => {
119+
document.getElementsByClassName('modal-title')[0].innerHTML = 'GPUs';
120+
let th_data = "<tr><th>Type</th><th>Vendor</th><th>Product</th></tr>";
121+
let td_data = "";
122+
processors.forEach(processor => {
123+
if (processor["processor_type"] === "GPU") {
124+
td_data += `<tr>`
125+
td_data += `<td>${processor["processor_type"]}</td>`
126+
td_data += `<td>${processor["vendor"]}</td>`
127+
td_data += `<td>${processor["product"]}</td>`
128+
td_data += `</tr>`
129+
}
130+
});
131+
document.getElementsByClassName('modal-body')[0].innerHTML = `<table class="table">${th_data}${td_data}</table>`;
132+
};
105133
$(document).ready( function () {
106134
const table = $('#results').DataTable({
107135
dom: 'Blfrtip',

0 commit comments

Comments
 (0)