From 5928bd31b9b18c9798bc7e0c96b58d797b7d58cb Mon Sep 17 00:00:00 2001 From: Salisu Ali Date: Mon, 23 Jan 2023 19:27:44 +0100 Subject: [PATCH 1/7] multiple identifiers --- src/Auth.js | 1 - src/app.js | 2 + src/app_server/routes/mainRouter.js | 8 +- src/app_server/views/metricdev.pug | 332 ++++++++++++++++++++++++++++ src/metrics.js | 121 ++++++---- src/nedbAdmin.js | 2 +- src/package-lock.json | 11 + src/package.json | 1 + 8 files changed, 428 insertions(+), 50 deletions(-) create mode 100644 src/app_server/views/metricdev.pug diff --git a/src/Auth.js b/src/Auth.js index 7f966b6..aff954f 100644 --- a/src/Auth.js +++ b/src/Auth.js @@ -49,7 +49,6 @@ module.exports.token = function(req, res){ res.json({accessToken: accessToken}) }) }); - }catch(err){ res.send("Token Generation Failed"); } diff --git a/src/app.js b/src/app.js index 0efc8bc..3e9eb55 100644 --- a/src/app.js +++ b/src/app.js @@ -27,6 +27,7 @@ var path = require('path'); var cookieParser = require('cookie-parser'); const fs = require('fs'); var session = require('express-session'); +const tls = require('tls'); const cors = require('cors'); const bodyParser = require('body-parser'); @@ -73,6 +74,7 @@ if(lpar_prom.length > 0){ } //require("./Eureka_conn"); process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0; +tls.DEFAULT_MIN_VERSION = "TLSv1.1"; var mainRouter = require('./app_server/routes/mainRouter'); var rmf3Router = require('./app_server/routes/rmf3Router'); var rmfppRouter = require('./app_server/routes/rmfppRouter'); diff --git a/src/app_server/routes/mainRouter.js b/src/app_server/routes/mainRouter.js index 373a6b1..fbcdd9a 100644 --- a/src/app_server/routes/mainRouter.js +++ b/src/app_server/routes/mainRouter.js @@ -62,9 +62,9 @@ function parameters(fn){ fn(parms); //return the parameters } -router.get('/pwdd', (req, res) => { //remember to delete +/* router.get('/pwdd', (req, res) => { //remember to delete res.render("login", {data: "pwd"}) -}) +}) */ // Checks if user login session is available in browser var sessionChecker = (req, res, next) => { @@ -201,9 +201,9 @@ router.get('/metrics', sessionChecker, (req, res) => { } //console.log(c); if(req.session.name){ //Check if User login session is available - res.render("metrics",{msg:"Admin", resources:resource, lpars:lpar, reports:REPORTS.RMFM3}); // render the metrics page wih Admin previledge + res.render("metricdev",{msg:"Admin", resources:resource, lpars:lpar, reports:REPORTS.RMFM3}); // render the metrics page wih Admin previledge }else{ - res.render("metrics", {resources:resource, lpars:lpar, reports:REPORTS.RMFM3}); + res.render("metricdev", {resources:resource, lpars:lpar, reports:REPORTS.RMFM3}); } }) diff --git a/src/app_server/views/metricdev.pug b/src/app_server/views/metricdev.pug new file mode 100644 index 0000000..9ab1f1d --- /dev/null +++ b/src/app_server/views/metricdev.pug @@ -0,0 +1,332 @@ +extends layout + +block header + link(rel='stylesheet', href='/stylesheets/slider.css') + style. + .center { + margin: 0; + position: absolute; + top: 50%; + left: 50%; + -ms-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); + } + + .container { + height: 200px; + position: relative; + } + + form { + --background: white; + --border: rgba(0, 0, 0, 0.125); + --borderDark: rgba(0, 0, 0, 0.25); + --borderDarker: rgba(0, 0, 0, 0.5); + --bgColorH: 0; + --bgColorS: 0%; + --bgColorL: 98%; + --fgColorH: 210; + --fgColorS: 50%; + --fgColorL: 38%; + --shadeDark: 0.3; + --shadeLight: 0.7; + --shadeNormal: 0.5; + --borderRadius: 0.125rem; + --highlight: #306090; + background: white; + border: 1px solid var(--border); + border-radius: var(--borderRadius); + box-shadow: 0 1rem 1rem -0.75rem var(--border); + display: flex; + flex-direction: column; + padding: 1rem; + position: relative; + overflow: hidden; + width:80%; + } + + .topa{ + width:80%; + margin: auto; + border: 1%; + padding: 10px; + } + + table { + font-family: arial, sans-serif; + border-collapse: collapse; + width: 96%; + } + + td, th { + border: 1px solid #dddddd; + text-align: left; + padding: 8px; + } + + tr:nth-child(even) { + background-color: #dddddd; + } + + /* Style the tab */ + .tab { + overflow: hidden; + border: 1px solid #ccc; + background-color: #f1f1f1; + } + + /* Style the buttons inside the tab */ + .tab button { + background-color: inherit; + float: left; + border: none; + outline: none; + cursor: pointer; + padding: 14px 16px; + transition: 0.3s; + font-size: 17px; + } + + /* Change background color of buttons on hover */ + .tab button:hover { + background-color: #ddd; + } + + /* Create an active/current tablink class */ + .tab button.active { + background-color: #ccc; + } + + /* Style the tab content */ + .tabcontent { + display: none; + padding: 6px 12px; + border: 1px solid #ccc; + border-top: none; + } + +block content + div(class="sidefm") + .salis(style={"width":"96%", "margin-top":"0px", "margin-bottom":"30px", "margin-left": "5%"}) + .row + h5(class='hdd') Add Custom Metrics + hr + div(class="tab") + button(class="tablinks" onclick="openCity(event, 'London')") New Metric + button(class="tablinks" onclick="openCity(event, 'Paris')") Existing Metric + div(id="London" class="tabcontent") + .row + form() + .row + .col-md-6 + label(style={"margin-top":"5px", "margin-right": "10px", "font-size":"12px"} for=`sysid`) SYSID + select.custom-select(class="form-control-sm" name="lpar" id="lpar" style={"margin-right": "10px"}) + option(selected='') Select LPAR + - for(dat of lpars) + option(value=`${dat}`) !{dat} + .col-md-6 + label(style={"margin-top":"5px", "margin-right": "10px", "font-size":"12px"} for=`rpt`) Report + select.custom-select(class="form-control-sm" name="rpt" id="rpt" style={"margin-right": "10px"} onchange="getrpt()") + option(selected='') Select + each report in reports + option(value=report) #{report} + label(style={"margin-top":"5px", "margin-right": "10px"} for="mid") Unique Metric id + input(type="text" class="form-control-sm" id=`umi` style={"margin-right": "10px"} placeholder=`e.g TOU for Total utilization`) + label(style={"margin-top":"5px", "margin-right": "10px"}) Resource + select.custom-select(class="form-control-sm" name="rst" id="rst" style={"margin-right": "10px"}) + option(selected='') Select Resource + - for(dt of resources) + option(value=`${dt}`) !{dt} + label(style={"margin-top":"5px", "margin-right": "10px"}) Identifier Key + select.custom-select(class="form-control-sm" name="prm" id="nid" style={"margin-right": "10px"} onchange="getnvl()") + option(selected='') Select + label(style={"margin-top":"5px", "margin-right": "10px"}) Identifier Value + select.custom-select(class="form-control-sm" name="nvl" id="snvl" style={"margin-right": "10px"}) + option(selected='*') ALL + label(style={"margin-top":"5px", "margin-right": "10px"}) Field + select.custom-select(class="form-control-sm" name="vrm" id="vid" style={"margin-right": "10px"}) + option(selected='') Select + label(style={"margin-top":"5px", "margin-right": "10px"}) Metric Description + input(type="text" class="form-control-sm" id=`umd` style={"margin-right": "10px"} placeholder=`A simple metrics description`) + + a(href='javascript:savemtr()' class='btn btn-primary' id="rmf3b", style={"margin-top":"13px", "width":"98%", "color":"white"}) Save + + div(id="Paris" class="tabcontent") + .salis(style={"width":"96%", "margin-top":"0px", "margin-bottom":"30px", "margin-left": "5%"}) + .row + form() + label(style={"margin-top":"5px", "margin-right": "10px"}) Metric + select.custom-select(class="form-control-sm" name="rst" id="rst" style={"margin-right": "10px"}) + option(selected='') Select Metric + - for(dt of resources) + option(value=`${dt}`) !{dt} + label(style={"margin-top":"5px", "margin-right": "10px"}) Identifier Key + select.custom-select(class="form-control-sm" name="prm" id="nid" style={"margin-right": "10px"} onchange="getnvl()") + option(selected='') Select + label(style={"margin-top":"5px", "margin-right": "10px"}) Identifier Value + select.custom-select(class="form-control-sm" name="nvl" id="snvl" style={"margin-right": "10px"}) + option(selected='*') ALL + + a(href='javascript:savemtr()' class='btn btn-primary' id="rmf3b", style={"margin-top":"13px", "width":"98%", "color":"white"}) Save + + + div(class="mainfm", style={"overflow" : "auto"}) + h5 Add Custom Metrics Page + p Use the form to add customize ZEBRA Prometheus Metrics. Note, you will need to first configure ZEBRA and have a working internet connection + br + p Full information on how the form works can be found in the ZEBRA documentation. + br + h5 Metrics Added + div(style={"overflow":"auto", "max-height":"50vh"}) + table(id="sctable") + tr + th Metric + th SYSID + th Report + th Resource + th Identifier Name + th Identifier Value + th field + th Action + + + +block scripts + script(src='https://code.jquery.com/jquery-3.5.1.min.js') + script(src='/stylesheets/bootstrap/js/bootstrap.min.js') + script(src='/stylesheets/bootstrap/js/bootstrap.bundle.min.js') + script. + + function gettbl(){ + $.ajax({ + dataType: "json", + type: 'get', + url: '/mtrfile' + }) + .done(function(e){ + //window.reloadTable("sctable"); + $.each(e.mtr, function(i){ + var len = $("#sctable tr").toArray().length; + var newRow = "" + +""+ e.mtr[i] +"" + +""+e.jsn[e.mtr[i]]["lpar"]+"" + +""+ e.jsn[e.mtr[i]]["request"]["report"] +"" + +""+e.jsn[e.mtr[i]]["request"]["resource"]+"" + +""+ e.jsn[e.mtr[i]]["identifiers"][0]["key"] +"" + +""+e.jsn[e.mtr[i]]["identifiers"][0]["value"]+"" + +""+e.jsn[e.mtr[i]]["field"]+"" + +`
Delete
` + +""; + $(newRow).appendTo("#sctable"); + }) + }); + } + + window.onload = function () { + gettbl(); + } + + function delmtr(a) { + var data = {ky: `${a}`}; + $.ajax({ + dataType: "json", + type: 'post', + url: '/delmtr', + data: data, + complete: function(data) { + if(data.status === 200){ + alert(`Metric Deleted Successfully`); + }else{ + alert(`Deleting Metric Failed`); + } + location.reload(); + } + }) + //.done(function(e){ + // gettbl(); + // alert(e); + //}); + } + + function getrpt() { + var data = {lpar: $("#lpar").val(), rpt: $("#rpt").val()}; + $.ajax({ + dataType: "json", + type: 'post', + url: '/getrpt', + data: data, + }) + .done(function(e){ + //alert(e.sc); + //window.reloadTable("nid"); + $.each(e.sc, function(i){ + var x = document.getElementById("nid"); + var c = document.createElement("option"); + c.text = e.sc[i]; + x.options.add(c, (i+1)); + }) + $.each(e.sc, function(i){ + var x = document.getElementById("vid"); + var c = document.createElement("option"); + c.text = e.sc[i]; + x.options.add(c, (i+1)); + }) + }); + } + + function getnvl() { + var data = {lpar: $("#lpar").val(), rpt: $("#rpt").val(), nid: $("#nid").val()}; + $.ajax({ + dataType: "json", + type: 'post', + url: '/getnvl', + data: data, + }) + .done(function(e){ + $.each(e.sc, function(i){ + var x = document.getElementById("snvl"); + var c = document.createElement("option"); + c.text = e.sc[i]; + x.options.add(c, (i+1)); + }) + }); + } + + function savemtr() { + var data = {lpar: $("#lpar").val(), rpt: $("#rpt").val(), nid: $("#nid").val(), umi: $("#umi").val(), umd: $("#umd").val(), snvl: $("#snvl").val(), vid: $("#vid").val(), rst: $("#rst").val() }; + $.ajax({ + dataType: "json", + type: 'post', + url: '/savemtr', + data: data, + complete: function(data) { + var c = `${$("#lpar").val()}_${$("#snvl").val()}_${$("#umi").val()}` + + if(data.status === 200){ + alert(`${c} Metric Saved Successfully`); + }else{ + alert(`Saving Metric Failed`); + } + + location.reload(); + + } + }) + //.done(function(e){ + // alert(e); + //}); + } + + function openCity(evt, cityName) { + var i, tabcontent, tablinks; + tabcontent = document.getElementsByClassName("tabcontent"); + for (i = 0; i < tabcontent.length; i++) { + tabcontent[i].style.display = "none"; + } + tablinks = document.getElementsByClassName("tablinks"); + for (i = 0; i < tablinks.length; i++) { + tablinks[i].className = tablinks[i].className.replace(" active", ""); + } + document.getElementById(cityName).style.display = "block"; + evt.currentTarget.className += " active"; + } \ No newline at end of file diff --git a/src/metrics.js b/src/metrics.js index 66379a9..6fd6a9b 100644 --- a/src/metrics.js +++ b/src/metrics.js @@ -53,54 +53,87 @@ setInterval(async () => { const result = response.data; for (const metricName in metrics) { var metric = metrics[metricName]; - // Check if users want data from all records in the JSON table having the metrics key - if(metric.identifiers[0].value === "ALL"){ - for (i in result['table']) { // loop through the entities - var mtrid = metricName.split("_")[2] // get the metric identifier provided by the user - var JSONBody = result['table'][i]; - var name = `${lpar}_${JSONBody[metric.identifiers[0].key]}_${mtrid}`; //append TOU(Total Utilization) to lpar name - var value = JSONBody[metric.field]; - try { - (new prometheus.Gauge({ - name: name, - help: metric.desc, - labelNames: ['parm'] - })).set({ - parm: metric.field - }, parseFloat(value)); - } catch (err) { - //console.log(err); + //Loop through Identifiers + for (var z in metric.identifiers) + { + // Check if users want data from all records in the JSON table having the metrics key + if(metric.identifiers[z].value === "ALL"){ + for (i in result['table']) { // loop through the entities + var mtrid = metricName.split("_")[2] // get the metric identifier provided by the user + var JSONBody = result['table'][i]; + var name = `${lpar}_${JSONBody[metric.identifiers[z].key]}_${metric.identifiers[z].key}`; //append TOU(Total Utilization) to lpar name + var value = JSONBody[metric.field]; + try { + (new prometheus.Gauge({ + name: name, + help: metric.desc, + labelNames: ['parm'] + })).set({ + parm: metric.field + }, parseFloat(value)); + } catch (err) { + //console.log(err); + } } - } - }else{ - if (metric.request.report === report && metric.request.resource === resource) { - // Get value of metric - var value = getValue(result, metric); - // If no match, log error and continue - if (!value) { - // console.log(`WARNING: Could not find field '${metric.field}' in report '${report}' for Prometheus metric '${metricName}'. Field could be missing because its value is 0, but make sure field is valid key.`); - continue; - } - // If non numeric value is chosen, log error and continue - if (!isNumeric(value)) { - console.log(`ERROR: Non-numeric error - the field '${metric.field}' in report '${report}' for Prometheus metric '${metricName}' is not numeric.`); - continue; - } - try{ - (new prometheus.Gauge({ - name: metricName, - help: metric.desc, - labelNames: ['parm'] - })).set({ - parm: metric.field - }, parseFloat(value)); - } catch(err) { - console.log(err); + }else{ + if (metric.request.report === report && metric.request.resource === resource) { + for (i in result['table']) { // loop through the entities + var mtrid = metricName.split("_")[2] // get the metric identifier provided by the user + var JSONBody = result['table'][i]; + if(JSONBody[metric.identifiers[z].key] == metric.identifiers[z].value) + { + var name = `${lpar}_${JSONBody[metric.identifiers[z].key]}_${metric.identifiers[z].key}`; //append TOU(Total Utilization) to lpar name + var value = JSONBody[metric.field]; + if (!value) { + // console.log(`WARNING: Could not find field '${metric.field}' in report '${report}' for Prometheus metric '${metricName}'. Field could be missing because its value is 0, but make sure field is valid key.`); + continue; + } + if (!isNumeric(value)) { + console.log(`ERROR: Non-numeric error - the field '${metric.field}' in report '${report}' for Prometheus metric '${metricName}' is not numeric.`); + continue; + } + try { + (new prometheus.Gauge({ + name: name, + help: metric.desc, + labelNames: ['parm'] + })).set({ + parm: metric.field + }, parseFloat(value)); + } catch (err) { + //console.log(err); + } + break; + } + + } + // Get value of metric + //var value = getValue(result, metric); + // If no match, log error and continue + /* if (!value) { + // console.log(`WARNING: Could not find field '${metric.field}' in report '${report}' for Prometheus metric '${metricName}'. Field could be missing because its value is 0, but make sure field is valid key.`); + continue; + } */ + // If non numeric value is chosen, log error and continue + /* if (!isNumeric(value)) { + console.log(`ERROR: Non-numeric error - the field '${metric.field}' in report '${report}' for Prometheus metric '${metricName}' is not numeric.`); + continue; + } + try{ + (new prometheus.Gauge({ + name: metricName, + help: metric.desc, + labelNames: ['parm'] + })).set({ + parm: metric.field + }, parseFloat(value)); + } catch(err) { + console.log(err); + } */ } } - } - + } } }) .catch((err) => { diff --git a/src/nedbAdmin.js b/src/nedbAdmin.js index de8505e..a503c9b 100644 --- a/src/nedbAdmin.js +++ b/src/nedbAdmin.js @@ -15,7 +15,7 @@ db = new sqlite3.Database('./admin.db', sqlite3.OPEN_READWRITE, (err) => { /* runQueries(db, function(data){ console.log(data); }); */ - console.log("Admin DB Created"); + console.log("Admin DB Started"); }); function createDatabase() { diff --git a/src/package-lock.json b/src/package-lock.json index 6ca1ad2..1e11816 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -37,6 +37,7 @@ "sqlite3": "^5.1.1", "swagger-ui-express": "^4.1.4", "sweetalert": "^2.1.2", + "tls": "^0.0.1", "xml2js": "^0.4.23" } }, @@ -3648,6 +3649,11 @@ "bintrees": "1.0.1" } }, + "node_modules/tls": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tls/-/tls-0.0.1.tgz", + "integrity": "sha512-GzHpG+hwupY8VMR6rYsnAhTHqT/97zT45PG8WD5eTT1lq+dFE0nN+1PYpsoBcHJgSmTz5ceK2Cv88IkPmIPOtQ==" + }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -6939,6 +6945,11 @@ "bintrees": "1.0.1" } }, + "tls": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tls/-/tls-0.0.1.tgz", + "integrity": "sha512-GzHpG+hwupY8VMR6rYsnAhTHqT/97zT45PG8WD5eTT1lq+dFE0nN+1PYpsoBcHJgSmTz5ceK2Cv88IkPmIPOtQ==" + }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", diff --git a/src/package.json b/src/package.json index e599069..272cec6 100644 --- a/src/package.json +++ b/src/package.json @@ -39,6 +39,7 @@ "sqlite3": "^5.1.1", "swagger-ui-express": "^4.1.4", "sweetalert": "^2.1.2", + "tls": "^0.0.1", "xml2js": "^0.4.23" } } From a4f1a98edab09f60516ab53ae0a950d1e6db6fb2 Mon Sep 17 00:00:00 2001 From: Salisu Ali Date: Mon, 23 Jan 2023 19:34:24 +0100 Subject: [PATCH 2/7] multiple identifiers --- src/admin.db | Bin 0 -> 12288 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/admin.db diff --git a/src/admin.db b/src/admin.db new file mode 100644 index 0000000000000000000000000000000000000000..71d1d29ddcc9d856327fba281db67f071885e07c GIT binary patch literal 12288 zcmeI#O>f#T7y#geZtJL2GKm9+U3}=IP1+FQBVBH#A)O2%84y0g1%+V1fdra_l5i_O zV*hLZW``YSs&zeVQ+L@8)BDO!V!ux8JU+S8(r84`bQO4Zgi72Cj_0`xggA~9SUqC( zK6v)<tMYOX?(`h5Jsp$4tv?hcDO#Ub|F6-U7mUaSW_r7q{$ppDfR zm)KoV;`ONGsZ>+yYirP=hN~9!U8`W2vt85G<^1Hz$C_vq+f=%iIvsM}wu3Eg+{9fk z8Qm1M*uu&*sgPK+{&aHDDfSZVuFtVonUDM3!)m2rzn)l~y8P>fG(+t5%7?#bnpR1# zwJL^*lV+)qk3V)djdo)$;+9j|xtFFPCYCf4Rpq*bJ+ Date: Mon, 23 Jan 2023 19:34:24 +0100 Subject: [PATCH 3/7] multiple identifiers --- src/admin.db | Bin 0 -> 12288 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/admin.db diff --git a/src/admin.db b/src/admin.db new file mode 100644 index 0000000000000000000000000000000000000000..71d1d29ddcc9d856327fba281db67f071885e07c GIT binary patch literal 12288 zcmeI#O>f#T7y#geZtJL2GKm9+U3}=IP1+FQBVBH#A)O2%84y0g1%+V1fdra_l5i_O zV*hLZW``YSs&zeVQ+L@8)BDO!V!ux8JU+S8(r84`bQO4Zgi72Cj_0`xggA~9SUqC( zK6v)<tMYOX?(`h5Jsp$4tv?hcDO#Ub|F6-U7mUaSW_r7q{$ppDfR zm)KoV;`ONGsZ>+yYirP=hN~9!U8`W2vt85G<^1Hz$C_vq+f=%iIvsM}wu3Eg+{9fk z8Qm1M*uu&*sgPK+{&aHDDfSZVuFtVonUDM3!)m2rzn)l~y8P>fG(+t5%7?#bnpR1# zwJL^*lV+)qk3V)djdo)$;+9j|xtFFPCYCf4Rpq*bJ+ Date: Tue, 10 Jan 2023 10:33:57 -0500 Subject: [PATCH 4/7] Create sample.metrics.json Signed-off-by: Alex KIM --- src/sample.metrics.json | 324 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 324 insertions(+) create mode 100644 src/sample.metrics.json diff --git a/src/sample.metrics.json b/src/sample.metrics.json new file mode 100644 index 0000000..92a8ce8 --- /dev/null +++ b/src/sample.metrics.json @@ -0,0 +1,324 @@ +{ + "RPRT_QCK2_PTOU": { + "lpar": "RPRT", + "request": { + "report": "CPC", + "resource": ",RPRT,MVS_IMAGE" + }, + "identifiers": [ + { + "key": "CPCPPNAM", + "value": "QCK2" + } + ], + "field": "CPCPPTOU", + "desc": "Physical total utilization for the QCK2 partition." + }, + "RPRT_TRNG_PTOU": { + "lpar": "RPRT", + "request": { + "report": "CPC", + "resource": ",RPRT,MVS_IMAGE" + }, + "identifiers": [ + { + "key": "CPCPPNAM", + "value": "TRNG" + } + ], + "field": "CPCPPTOU", + "desc": "Physical total utilization for the TRNG partition." + }, + "RPRT_VIDVLP_PTOU": { + "lpar": "RPRT", + "request": { + "report": "CPC", + "resource": ",RPRT,MVS_IMAGE" + }, + "identifiers": [ + { + "key": "CPCPPNAM", + "value": "VIDVLP" + } + ], + "field": "CPCPPTOU", + "desc": "Physical total utilization for the VIDVLP partition." + }, + "RPRT_VIRPT_PTOU": { + "lpar": "RPRT", + "request": { + "report": "CPC", + "resource": ",RPRT,MVS_IMAGE" + }, + "identifiers": [ + { + "key": "CPCPPNAM", + "value": "VIRPT" + } + ], + "field": "CPCPPTOU", + "desc": "Physical total utilization for the VIRPT partition." + }, + "RPRT_KVMOCP1_PTOU": { + "lpar": "RPRT", + "request": { + "report": "CPC", + "resource": ",RPRT,MVS_IMAGE" + }, + "identifiers": [ + { + "key": "CPCPPNAM", + "value": "KVMOCP1" + } + ], + "field": "CPCPPTOU", + "desc": "Physical total utilization for the KVMOCP1 partition." + }, + "RPRT_KVMOCP2_PTOU": { + "lpar": "RPRT", + "request": { + "report": "CPC", + "resource": ",RPRT,MVS_IMAGE" + }, + "identifiers": [ + { + "key": "CPCPPNAM", + "value": "KVMOCP2" + } + ], + "field": "CPCPPTOU", + "desc": "Physical total utilization for the KVMOCP2 partition." + }, + "RPRT_ZVMPROD_PTOU": { + "lpar": "RPRT", + "request": { + "report": "CPC", + "resource": ",RPRT,MVS_IMAGE" + }, + "identifiers": [ + { + "key": "CPCPPNAM", + "value": "ZVMPROD" + } + ], + "field": "CPCPPTOU", + "desc": "Physical total utilization for the ZVMPROD partition." + }, + "LPAR_MEM_QCK2": { + "lpar": "RPRT", + "request": { + "report": "CPC", + "resource": ",RPRT,MVS_IMAGE" + }, + "identifiers": [ + { + "key": "CPCPPNAM", + "value": "QCK2" } + ], + "field": "CPCPCSMB", + "desc": "Central storage in MB for the partition." + }, + "LPAR_MEM_TRNG": { + "lpar": "RPRT", + "request": { + "report": "CPC", + "resource": ",RPRT,MVS_IMAGE" + }, + "identifiers": [ + { + "key": "CPCPPNAM", + "value": "TRNG" } + ], + "field": "CPCPCSMB", + "desc": "Central storage in MB for the partition." + }, + + "LPAR_MEM_RPRT": { + "lpar": "RPRT", + "request": { + "report": "CPC", + "resource": ",RPRT,MVS_IMAGE" + }, + "identifiers": [ + { + "key": "CPCPPNAM", + "value": "VIRPT" } + ], + "field": "CPCPCSMB", + "desc": "Central storage in MB for the partition." + }, + + "LPAR_MEM_DVLP": { + "lpar": "RPRT", + "request": { + "report": "CPC", + "resource": ",RPRT,MVS_IMAGE" + }, + "identifiers": [ + { + "key": "CPCPPNAM", + "value": "VIDVLP" } + ], + "field": "CPCPCSMB", + "desc": "Central storage in MB for the partition." + }, + + + + "RPRT_ALL_SYSINFO_SYSUGPVC": { + "lpar": "RPRT", + "request": { + "report": "SYSINFO", + "resource": ",RPRT,MVS_IMAGE" + }, + "identifiers": [ + { + "key": "SYSNAMVC", + "value": "ALL" + } + ], + "field": "SYSCPUVC", + "desc": "WLM SYSINFO for % Using processor" + }, + + "RPRT_ALL_SYSINFO_SYSPDPVC": { + "lpar": "RPRT", + "request": { + "report": "SYSINFO", + "resource": ",RPRT,MVS_IMAGE" + }, + "identifiers": [ + { + "key": "SYSNAMVC", + "value": "ALL" + } + ], + "field": "SYSPDPVC", + "desc": "WLM SYSINFO for CPU Time in Secs" + }, + + + + "RPRT_ALL_USAGE": { + "lpar": "RPRT", + "request": { + "report": "USAGE", + "resource": ",RPRT,MVS_IMAGE" + }, + "identifiers": [ + { + "key": "JUSPJOB", + "value": "ALL" + } + ], + "field": "JUSPCPUD", + "desc": "CPU time for interval (in seconds)" + }, + + + + "RPRT_ALL_CSXAECS": { + "lpar": "RPRT", + "request": { + "report": "STORC", + "resource": ",RPRT,MVS_IMAGE" + }, + "identifiers": [ + { + "key": "CSXNAME", + "value": "ALL" + } + ], + "field": "CSXAECS", + "desc": "Common Storagei - Amount of ECSA" + }, + "RPRT_ALL_CSXACSA": { + "lpar": "RPRT", + "request": { + "report": "STORC", + "resource": ",RPRT,MVS_IMAGE" + }, + "identifiers": [ + { + "key": "CSXNAME", + "value": "ALL" + } + ], + "field": "CSXACSA", + "desc": "Common Storagei - Amount of CSA" + }, + "RPRT_ALL_JDELDEL": { + "lpar": "RPRT", + "request": { + "report": "DELAY", + "resource": ",RPRT,MVS_IMAGE" + }, + "identifiers": [ + { + "key": "JDELDAN", + "value": "ALL" + } + ], + "field": "JDELDEL", + "desc": "Job Processing Delay percentage" + }, + "RPRT_00_OSC_CHACPUVC": { + "lpar": "RPRT", + "request": { + "report": "CHANNEL", + "resource": ",RPRT,MVS_IMAGE" + }, + "identifiers": [ + { + "key": "CHACPIVC", + "value": "00" + }, + { + "key": "CHACPTVC", + "value": "OSC" + } + ], + "field": "CHACPUVC", + "desc": "Channel - Part util %" + }, + "RPRT_01_OSD_CHACPUVC": { + "lpar": "RPRT", + "request": { + "report": "CHANNEL", + "resource": ",RPRT,MVS_IMAGE" + }, + "identifiers": [ + { + "key": "CHACPIVC", + "value": "01" + }, + { + "key": "CHACPTVC", + "value": "OSD" + } + ], + + "field": "CHACPUVC", + "desc": "Channel - Partition util %" + }, + "RPRT_10_FC_CHACPUVC": { + "lpar": "RPRT", + "request": { + "report": "CHANNEL", + "resource": ",RPRT,MVS_IMAGE" + }, + "identifiers": [ + { + "key": "CHACPIVC", + "value": "10" + }, + { + "key": "CHACPTVC", + "value": "FC" + } + ], + "field": "CHACPUVC", + "desc": "Channel - Partition util %" + } + +} From 34e0d5463a4e75433604955b8531f58281c1e615 Mon Sep 17 00:00:00 2001 From: Salisu Ali Date: Fri, 3 Mar 2023 18:13:15 +0100 Subject: [PATCH 5/7] mul identifier II Signed-off-by: Salisu Ali --- src/admin.db | Bin 12288 -> 12288 bytes src/metrics.js | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/admin.db b/src/admin.db index 71d1d29ddcc9d856327fba281db67f071885e07c..f749b1486caa5701213fcb2dcff045393533ecd6 100644 GIT binary patch delta 158 zcmZojXh@hK%_uZc#+gxQW5Ovpvt$#$kYq!@suW8-mlW^(H1iy{vH*j8Q(v>tGDBw* zgOJd4b8~Ow^z6!F$BML^EZx#5SA*io3G%@{Fs;eOp1ENr$<{iALp>CS?Vck;SG-mTsH>%QFf9 E0I&%&CIA2c delta 158 zcmZojXh@hK&B#Ad#+i|SW5Ovpvp@s?kn}3wEI&)V6t_H2A47kmpiHwuv*6%V^Pt3{ z@=WitiqPE3_%b7(ibzlAv`W*|3ZKZy3G%@{Fs;7Dp1ENr$ { for (i in result['table']) { // loop through the entities var mtrid = metricName.split("_")[2] // get the metric identifier provided by the user var JSONBody = result['table'][i]; - var name = `${lpar}_${JSONBody[metric.identifiers[z].key]}_${metric.identifiers[z].key}`; //append TOU(Total Utilization) to lpar name + var name = `${lpar}_${JSONBody[metric.identifiers[z].key]}_${metric.identifiers[z].desc}`; //append TOU(Total Utilization) to lpar name var value = JSONBody[metric.field]; try { (new prometheus.Gauge({ @@ -83,7 +83,7 @@ setInterval(async () => { var JSONBody = result['table'][i]; if(JSONBody[metric.identifiers[z].key] == metric.identifiers[z].value) { - var name = `${lpar}_${JSONBody[metric.identifiers[z].key]}_${metric.identifiers[z].key}`; //append TOU(Total Utilization) to lpar name + var name = `${lpar}_${JSONBody[metric.identifiers[z].key]}_${metric.identifiers[z].desc}`; //append TOU(Total Utilization) to lpar name var value = JSONBody[metric.field]; if (!value) { // console.log(`WARNING: Could not find field '${metric.field}' in report '${report}' for Prometheus metric '${metricName}'. Field could be missing because its value is 0, but make sure field is valid key.`); From 6c3b0c6b45517c4b734a6e55e446c5c1f8683fbb Mon Sep 17 00:00:00 2001 From: Salisu Ali Date: Thu, 9 Mar 2023 18:38:33 +0100 Subject: [PATCH 6/7] Metrics User Interface Signed-off-by: Salisu Ali --- .../User Documentation/9. create_metrics.md | 101 ++++++++ src/.dockerignore | 1 + src/admin.db | Bin 12288 -> 12288 bytes src/app_server/routes/mainRouter.js | 97 +++++++- src/app_server/views/metricdev.pug | 232 ++++++++++++++---- src/metrics.js | 24 +- 6 files changed, 392 insertions(+), 63 deletions(-) create mode 100644 Documentation/User Documentation/9. create_metrics.md diff --git a/Documentation/User Documentation/9. create_metrics.md b/Documentation/User Documentation/9. create_metrics.md new file mode 100644 index 0000000..bea06a1 --- /dev/null +++ b/Documentation/User Documentation/9. create_metrics.md @@ -0,0 +1,101 @@ +# The New Metrics User Interface + The new Metrics User Interface for ZEBRA allows users to create and delete custom metrics for prometheus. It contains two forms: New metrics and Existing metrics form. It also displays Metrics already created by the user and users can view and delete these metrics. + +# Terminilogies + **Metric** : This represented an RMF III report and its LPAR. its format is LPAR_REPORT e.g RPRT_CPC, RPRT_CHANNEL, RPRT_SYSINFO. Only one metric can be created for each report in a single LPAR. This means only one CPC report can exist for RPRT LPAR. Below is an example of a CPC metric +``` + "RPRT_CPC": { + "lpar": "RPRT", + "request": { + "report": "CPC", + "resource": ",RPRT,MVS_IMAGE" + }, + "identifiers": [ + + ] + } +``` + + **Identifiers** : This represent the parameters required to build a prometheus client metric from a Report. e.g parameters from CPC report needed to create a Total Utilization or effective utilization prometheus metric in ZEBRA. Each Metric can have multiple identifiers. Identifiers has 5 parameters: + - **Identifier Key**: This represent the parameter in a report that has a Unique value you will like to monitor. e.g CPCHPNAM in That represent Name of partition that collected the data in CPC report + - **Identifier Value**: This takes either ALL(to represent all Identifier key values) or a specific value for the identifier key (e.g VIRPT for CPCHPNAM in CPC report to signify intrest in only VIRPT LPAR data) + - **Metric ID (m_id)**: This is a unique ID selected by user to represent the Identifier (e.g TOU for Total Utilization, EFU for effective utilization) + - **Field**: This represent a numeric field in the report from which the number will be used to plot a chart in grafana. e.g CPCPLTOU which represent Logical processor total utilization, CPCPLEFU which represent Logical processor effective utilization in CPC Report + - **Description (desc)**: This is a user choosen description for the identifier + + Below is an example of CPC metric with Total Utilization and Effective Utilization Identifiers +``` + "RPRT_CPC": { + "lpar": "RPRT", + "request": { + "report": "CPC", + "resource": ",RPRT,MVS_IMAGE" + }, + "identifiers": [ + { + "field": "CPCPLTOU", + "key": "CPCPPNAM", + "value": "ALL", + "m_id": "TOU", + "desc": "CPC Total Utilization" + }, + { + "key": "CPCPPNAM", + "value": "ALL", + "field": "CPCPLEFU", + "m_id": "EFU", + "desc": "Effective Utilization" + } + ] + } +``` + **Prometheus Metric** : These are the final metrics created by ZEBRA and exposed through http(s)://ZEBRA Ip:port/prommetric Endpoint. They are of the folloeing format: + ``` + {LPAR}_{IDENTIFIER_VALUE}_{METRIC_ID} + ``` + + example of ZEBRA Prometheus Metrics + +``` +# HELP RPRT_TRNG_TOU CPC Total Utilization +# TYPE RPRT_TRNG_TOU gauge +RPRT_TRNG_TOU{parm="CPCPLTOU"} 0.4 + +# HELP RPRT_VIDVLP_TOU CPC Total Utilization +# TYPE RPRT_VIDVLP_TOU gauge +RPRT_VIDVLP_TOU{parm="CPCPLTOU"} 0.5 + +# HELP RPRT_VIRPT_TOU CPC Total Utilization +# TYPE RPRT_VIRPT_TOU gauge +RPRT_VIRPT_TOU{parm="CPCPLTOU"} 0.5 + +# HELP RPRT_TRNG_EFU Effective Utilization +# TYPE RPRT_TRNG_EFU gauge +RPRT_TRNG_EFU{parm="CPCPLEFU"} 0.4 + +# HELP RPRT_VIDVLP_EFU Effective Utilization +# TYPE RPRT_VIDVLP_EFU gauge +RPRT_VIDVLP_EFU{parm="CPCPLEFU"} 0.4 + +# HELP RPRT_VIRPT_EFU Effective Utilization +# TYPE RPRT_VIRPT_EFU gauge +RPRT_VIRPT_EFU{parm="CPCPLEFU"} 0.5 +``` + +# How To create a Metric +- Using the metrics user interface (http://zebraIP:port/metrics) +- Click on New Metric. Use this form to add a new metric with one identifier +- Click Save + +# How to Add Identifiers +- Using the metrics user interface (http://zebraIP:port/metrics) +- Click on Existing Metric +- Select The Metric from the drop Down +- Fill the form +- Click Save + +# View and Delete Metric/Identifier +- From the dropdown under metrics added in the center of the page +- Select a metric to view it details +- Click Delete ID to delete a single identifier +- Click Delete Metric to delete the metric and its Identifiers diff --git a/src/.dockerignore b/src/.dockerignore index e42e335..1949651 100644 --- a/src/.dockerignore +++ b/src/.dockerignore @@ -3,6 +3,7 @@ db data my.db my.dbrefresh +admin.db # node modules node_modules diff --git a/src/admin.db b/src/admin.db index f749b1486caa5701213fcb2dcff045393533ecd6..2a6f0e234d2d902f20de2b8d06d29083c3e32afc 100644 GIT binary patch delta 157 zcmZojXh@hK&FC;u#+lJ!W5Ovpv-B!|7e`~i5I0M`c&FgxJddQ*N*CWUzp~WQ^msGZ z2;Y$SBu~fkaMJ+KER*>BNYg4mBj57L3G%_dFs-h|p1ENr$tGDBw* zgOJd4b8~Ow^z6!F$BML^EZx#5SA*io3G%_dFs;eOp1ENr$<{iALp>CS?Vck;SG-mTsYo6a)Zz CwlZu0 diff --git a/src/app_server/routes/mainRouter.js b/src/app_server/routes/mainRouter.js index fbcdd9a..79b20db 100644 --- a/src/app_server/routes/mainRouter.js +++ b/src/app_server/routes/mainRouter.js @@ -57,7 +57,7 @@ function parameters(fn){ usePrometheus: Zconfig.usePrometheus, https: Zconfig.https, grafanaurl: Zconfig.grafanaurl, - grafanaport: Zconfig.grafanaport + grafanaport: Zconfig.grafanaport } fn(parms); //return the parameters } @@ -96,6 +96,49 @@ router.post('/delmtr', (req, res) => { }); }); +router.post('/delid', (req, res) => { + fs.readFile('metrics.json', (err, data) => { + if (err) throw err; + let metricsfile = JSON.parse(data); + var id_len = metricsfile[req.body.ky]["identifiers"].length; + for(i=0; i < id_len; i++){ + if (metricsfile[req.body.ky]["identifiers"][i]["m_id"] == req.body.id){ + metricsfile[req.body.ky]["identifiers"].splice(i,1); + break; + } + } + fs.writeFile("metrics.json", JSON.stringify(metricsfile, null, '\t'), 'utf-8', function(err, data) { + res.send("Metric ID Deleted Successfully"); + }); + }); +}); + + +router.get('/getmetr', (req, res) => { + fs.readFile('metrics.json', (err, data) => { + if (err) throw err; + let metricsfile = JSON.parse(data); + res.send({sc:Object.keys(metricsfile)}); + }); +}) + +router.post('/getmetricdis', (req, res) => { + try{ + var metric = req.body.metric; + fs.readFile('metrics.json', (err, data) => { + if (err) throw err; + let metricsfile = JSON.parse(data); + let mtr = metricsfile[metric] + res.send({sysid: mtr.lpar, rpt: mtr.request.report, rsc: mtr.request.resource, ids:mtr.identifiers}); + }); + + }catch(err){ + res.send("error") + + } + +}) + router.post('/savemtr', (req, res) => { try{ var lpar = req.body.lpar; @@ -106,7 +149,7 @@ router.post('/savemtr', (req, res) => { var umi = req.body.umi; var umd = req.body.umd; var rst = req.body.rst; - var key = `${lpar}_${snvl}_${umi}`; + var key = `${lpar}_${rpt}`; var mtr = JSON.parse(`{ "lpar": "${lpar}", "request": { @@ -116,18 +159,56 @@ router.post('/savemtr', (req, res) => { "identifiers": [ { "key": "${nid}", - "value": "${snvl}" + "value": "${snvl}", + "field": "${vid}", + "m_id": "${umi}", + "desc": "${umd}" } - ], - "field": "${vid}", - "desc": "${umd}" + ] }`) fs.readFile('metrics.json', (err, data) => { if (err) throw err; let metricsfile = JSON.parse(data); - metricsfile[`${key}`] = mtr + metrkeys = Object.keys(metricsfile); + if(metrkeys.includes(key)){ + res.status(304).send(); + }else { + metricsfile[`${key}`] = mtr + fs.writeFile("metrics.json", JSON.stringify(metricsfile, null, '\t'), 'utf-8', function(err, data) { + res.send("Metric Added Successfully"); + }); + } + }); + + }catch(err){ + res.send("error") + } +}) + +router.post('/saveexmtr', (req, res) => { + try{ + var metr = req.body.metr; + var nidex = req.body.nidex; + var snvlex = req.body.snvlex; + var videx = req.body.videx; + var umiex = req.body.umiex; + var umdex = req.body.umdex; + var idf = JSON.parse(` + { + + "key": "${nidex}", + "value": "${snvlex}", + "field": "${videx}", + "m_id": "${umiex}", + "desc": "${umdex}" + } + `) + fs.readFile('metrics.json', (err, data) => { + if (err) throw err; + let metricsfile = JSON.parse(data); + (metricsfile[`${metr}`]["identifiers"]).push(idf) fs.writeFile("metrics.json", JSON.stringify(metricsfile, null, '\t'), 'utf-8', function(err, data) { - res.send("Metric Added Successfully"); + res.send("Metric Identifier Successfully"); }); }); diff --git a/src/app_server/views/metricdev.pug b/src/app_server/views/metricdev.pug index 9ab1f1d..071fd48 100644 --- a/src/app_server/views/metricdev.pug +++ b/src/app_server/views/metricdev.pug @@ -108,13 +108,11 @@ block header block content div(class="sidefm") .salis(style={"width":"96%", "margin-top":"0px", "margin-bottom":"30px", "margin-left": "5%"}) - .row - h5(class='hdd') Add Custom Metrics - hr + div(class="tab") - button(class="tablinks" onclick="openCity(event, 'London')") New Metric - button(class="tablinks" onclick="openCity(event, 'Paris')") Existing Metric - div(id="London" class="tabcontent") + button(class="tablinks" onclick="openTab(event, 'New')") New Metric + button(class="tablinks" onclick="openTab(event, 'Existing')") Existing Metric + div(id="New" class="tabcontent") .row form() .row @@ -151,23 +149,29 @@ block content a(href='javascript:savemtr()' class='btn btn-primary' id="rmf3b", style={"margin-top":"13px", "width":"98%", "color":"white"}) Save - div(id="Paris" class="tabcontent") + div(id="Existing" class="tabcontent") .salis(style={"width":"96%", "margin-top":"0px", "margin-bottom":"30px", "margin-left": "5%"}) .row form() - label(style={"margin-top":"5px", "margin-right": "10px"}) Metric - select.custom-select(class="form-control-sm" name="rst" id="rst" style={"margin-right": "10px"}) + label(style={"margin-top":"5px", "margin-right": "10px"}) Metric(s) + select.custom-select(class="form-control-sm" name="metr" id="metr" style={"margin-right": "10px"} onchange="getrptex()") option(selected='') Select Metric - - for(dt of resources) - option(value=`${dt}`) !{dt} + label(style={"margin-top":"5px", "margin-right": "10px"} for="mid") Unique Metric id + input(type="text" class="form-control-sm" id=`umiex` style={"margin-right": "10px"} placeholder=`e.g TOU for Total utilization`) label(style={"margin-top":"5px", "margin-right": "10px"}) Identifier Key - select.custom-select(class="form-control-sm" name="prm" id="nid" style={"margin-right": "10px"} onchange="getnvl()") + select.custom-select(class="form-control-sm" name="prmex" id="nidex" style={"margin-right": "10px"} onchange="getnvlex()") option(selected='') Select label(style={"margin-top":"5px", "margin-right": "10px"}) Identifier Value - select.custom-select(class="form-control-sm" name="nvl" id="snvl" style={"margin-right": "10px"}) + select.custom-select(class="form-control-sm" name="nvlex" id="snvlex" style={"margin-right": "10px"}) option(selected='*') ALL + label(style={"margin-top":"5px", "margin-right": "10px"}) Field + select.custom-select(class="form-control-sm" name="vrmex" id="videx" style={"margin-right": "10px"}) + option(selected='') Select + label(style={"margin-top":"5px", "margin-right": "10px"}) Metric Description + input(type="text" class="form-control-sm" id=`umdex` style={"margin-right": "10px"} placeholder=`A simple metrics description`) + - a(href='javascript:savemtr()' class='btn btn-primary' id="rmf3b", style={"margin-top":"13px", "width":"98%", "color":"white"}) Save + a(href='javascript:saveexmtr()' class='btn btn-primary' id="rmf3b", style={"margin-top":"13px", "width":"98%", "color":"white"}) Save div(class="mainfm", style={"overflow" : "auto"}) @@ -175,20 +179,36 @@ block content p Use the form to add customize ZEBRA Prometheus Metrics. Note, you will need to first configure ZEBRA and have a working internet connection br p Full information on how the form works can be found in the ZEBRA documentation. - br h5 Metrics Added div(style={"overflow":"auto", "max-height":"50vh"}) + .row(style={"margin-right": "30px", "margin-left": "10px"}) + label(style={"margin-top":"5px", "margin-right": "10px"}) Metric(s) + select.custom-select(class="form-control-sm" name="metrdis" id="metrdis" style={"margin-right": "10px"} onchange="getmetrdis()") + option(selected='') Select Metric + div(style={"clear": "both", "margin-top":"10px"}) + p(style={"float": "left", "font-size": "18px"}) SYSID: + p(id="sysid" style={"font-weight": "bold", "float": "right", "margin-left":"5px", "font-size": "18px"}) + hr + div(style={"clear": "both", "margin-top":"10px"}) + p(style={"float": "left", "font-size": "18px"}) Report: + p(id="rptdis" style={"font-weight": "bold", "float": "right", "margin-left":"5px", "font-size": "18px"}) + hr + div(style={"clear": "both", "margin-top":"10px"}) + p(style={"float": "left", "font-size": "18px"}) Resource: + p(id="rsc" style={"font-weight": "bold", "float": "right", "margin-left":"5px", "font-size": "18px"}) + hr + div(style={"clear": "both", "margin-top":"10px"}) + a(href='javascript:delmtr()' class='btn btn-danger' id="rmf3b", style={ "width":"100%", "float": "left", "color":"white"}) Delete Metric + table(id="sctable") tr - th Metric - th SYSID - th Report - th Resource - th Identifier Name + th Identifier Name th Identifier Value - th field + th Field + th Metric ID + th Description th Action - + block scripts @@ -196,8 +216,40 @@ block scripts script(src='/stylesheets/bootstrap/js/bootstrap.min.js') script(src='/stylesheets/bootstrap/js/bootstrap.bundle.min.js') script. + + function getmetrdis() { + var data = {metric: $("#metrdis").val()}; + $.ajax({ + dataType: "json", + type: 'post', + url: '/getmetricdis', + data: data, + }) + .done(function(e){ + //window.reloadTable("sctable"); + //$("#sctable > tr").empty(); + $('#sysid').text(`${e.sysid}`) + $('#rptdis').text(`${e.rpt}`) + $('#rsc').text(`${e.rsc}`) + $("#sctable").find("tr:gt(0)").remove(); + $.each(e.ids, function(i){ + var len = $("#sctable tr").toArray().length; + var newRow = "" + +""+ e.ids[i]["key"] +"" + +""+e.ids[i]["value"]+"" + +""+e.ids[i]["field"]+"" + +""+e.ids[i]["m_id"]+"" + +""+e.ids[i]["desc"]+"" + +`` + +""; + $(newRow).appendTo("#sctable"); + }) + }); + } function gettbl(){ + //$("#sctable > tr").empty(); + $("#sctable").find("tr:gt(0)").remove(); $.ajax({ dataType: "json", type: 'get', @@ -205,17 +257,16 @@ block scripts }) .done(function(e){ //window.reloadTable("sctable"); + $.each(e.mtr, function(i){ var len = $("#sctable tr").toArray().length; var newRow = "" +""+ e.mtr[i] +"" +""+e.jsn[e.mtr[i]]["lpar"]+"" - +""+ e.jsn[e.mtr[i]]["request"]["report"] +"" - +""+e.jsn[e.mtr[i]]["request"]["resource"]+"" +""+ e.jsn[e.mtr[i]]["identifiers"][0]["key"] +"" +""+e.jsn[e.mtr[i]]["identifiers"][0]["value"]+"" - +""+e.jsn[e.mtr[i]]["field"]+"" - +`` + +""+e.jsn[e.mtr[i]]["identifiers"][0]["field"]+"" + +`` +""; $(newRow).appendTo("#sctable"); }) @@ -223,11 +274,13 @@ block scripts } window.onload = function () { - gettbl(); + gettmetr("metrdis"); + //gettbl(); + } - function delmtr(a) { - var data = {ky: `${a}`}; + function delmtr() { + var data = {ky: $("#metrdis").val()}; $.ajax({ dataType: "json", type: 'post', @@ -242,10 +295,25 @@ block scripts location.reload(); } }) - //.done(function(e){ - // gettbl(); - // alert(e); - //}); + } + + function del_id(a) { + var metr = $("#metrdis").val(); + var data = {ky: metr, id:a}; + $.ajax({ + dataType: "json", + type: 'post', + url: '/delid', + data: data, + complete: function(data) { + if(data.status === 200){ + alert(`${metr} Metric ${a} Identifier Deleted Successfully`); + }else{ + alert(`Deleting Metric Identifier Failed`); + } + location.reload(); + } + }) } function getrpt() { @@ -257,8 +325,6 @@ block scripts data: data, }) .done(function(e){ - //alert(e.sc); - //window.reloadTable("nid"); $.each(e.sc, function(i){ var x = document.getElementById("nid"); var c = document.createElement("option"); @@ -274,6 +340,33 @@ block scripts }); } + function getrptex() { + var mtrx = $("#metr").val().split("_") + var data = {lpar: mtrx[0], rpt: mtrx[1]}; + $.ajax({ + dataType: "json", + type: 'post', + url: '/getrpt', + data: data, + }) + .done(function(e){ + //alert(e.sc); + //window.reloadTable("nid"); + $.each(e.sc, function(i){ + var x = document.getElementById("nidex"); + var c = document.createElement("option"); + c.text = e.sc[i]; + x.options.add(c, (i+1)); + }) + $.each(e.sc, function(i){ + var x = document.getElementById("videx"); + var c = document.createElement("option"); + c.text = e.sc[i]; + x.options.add(c, (i+1)); + }) + }); + } + function getnvl() { var data = {lpar: $("#lpar").val(), rpt: $("#rpt").val(), nid: $("#nid").val()}; $.ajax({ @@ -292,6 +385,25 @@ block scripts }); } + function getnvlex() { + var mtrx = $("#metr").val().split("_") + var data = {lpar: mtrx[0], rpt: mtrx[1], nid: $("#nidex").val()}; + $.ajax({ + dataType: "json", + type: 'post', + url: '/getnvl', + data: data, + }) + .done(function(e){ + $.each(e.sc, function(i){ + var x = document.getElementById("snvlex"); + var c = document.createElement("option"); + c.text = e.sc[i]; + x.options.add(c, (i+1)); + }) + }); + } + function savemtr() { var data = {lpar: $("#lpar").val(), rpt: $("#rpt").val(), nid: $("#nid").val(), umi: $("#umi").val(), umd: $("#umd").val(), snvl: $("#snvl").val(), vid: $("#vid").val(), rst: $("#rst").val() }; $.ajax({ @@ -300,25 +412,59 @@ block scripts url: '/savemtr', data: data, complete: function(data) { - var c = `${$("#lpar").val()}_${$("#snvl").val()}_${$("#umi").val()}` + var c = `${$("#lpar").val()}_${$("#rpt").val()}` if(data.status === 200){ alert(`${c} Metric Saved Successfully`); + }else if(data.status === 304){ + alert(`Metric Already Exist`); }else{ alert(`Saving Metric Failed`); } - location.reload(); - } }) - //.done(function(e){ - // alert(e); - //}); } - function openCity(evt, cityName) { + function saveexmtr() { + var data = {metr: $("#metr").val(), nidex: $("#nidex").val(), umiex: $("#umiex").val(), umdex: $("#umdex").val(), snvlex: $("#snvlex").val(), videx: $("#videx").val()}; + $.ajax({ + dataType: "json", + type: 'post', + url: '/saveexmtr', + data: data, + complete: function(data) { + var c = `${$("#metr").val()}` + + if(data.status === 200){ + alert(`${c} Metric Identifier Saved Successfully`); + }else{ + alert(`Saving Metric Identifier Failed`); + } + location.reload(); + } + }) + } + function gettmetr(elem){ + $.ajax({ + dataType: "json", + type: 'get', + url: '/getmetr' + }) + .done(function(e){ + $.each(e.sc, function(i){ + var x = document.getElementById(`${elem}`); + var c = document.createElement("option"); + c.text = e.sc[i]; + x.options.add(c, (i+1)); + }) + }); + } + function openTab(evt, Name) { var i, tabcontent, tablinks; + if(Name == "Existing"){ + gettmetr("metr"); + } tabcontent = document.getElementsByClassName("tabcontent"); for (i = 0; i < tabcontent.length; i++) { tabcontent[i].style.display = "none"; @@ -327,6 +473,6 @@ block scripts for (i = 0; i < tablinks.length; i++) { tablinks[i].className = tablinks[i].className.replace(" active", ""); } - document.getElementById(cityName).style.display = "block"; + document.getElementById(Name).style.display = "block"; evt.currentTarget.className += " active"; } \ No newline at end of file diff --git a/src/metrics.js b/src/metrics.js index e1bf370..d95c38b 100644 --- a/src/metrics.js +++ b/src/metrics.js @@ -61,15 +61,15 @@ setInterval(async () => { for (i in result['table']) { // loop through the entities var mtrid = metricName.split("_")[2] // get the metric identifier provided by the user var JSONBody = result['table'][i]; - var name = `${lpar}_${JSONBody[metric.identifiers[z].key]}_${metric.identifiers[z].desc}`; //append TOU(Total Utilization) to lpar name - var value = JSONBody[metric.field]; + var name = `${lpar}_${JSONBody[metric.identifiers[z].key]}_${metric.identifiers[z].m_id}`; //append TOU(Total Utilization) to lpar name + var value = JSONBody[metric.identifiers[z].field]; try { (new prometheus.Gauge({ name: name, - help: metric.desc, + help: metric.identifiers[z].desc, labelNames: ['parm'] })).set({ - parm: metric.field + parm: metric.identifiers[z].field }, parseFloat(value)); } catch (err) { //console.log(err); @@ -83,23 +83,23 @@ setInterval(async () => { var JSONBody = result['table'][i]; if(JSONBody[metric.identifiers[z].key] == metric.identifiers[z].value) { - var name = `${lpar}_${JSONBody[metric.identifiers[z].key]}_${metric.identifiers[z].desc}`; //append TOU(Total Utilization) to lpar name - var value = JSONBody[metric.field]; + var name = `${lpar}_${JSONBody[metric.identifiers[z].key]}_${metric.identifiers[z].m_id}`; //append TOU(Total Utilization) to lpar name + var value = JSONBody[metric.identifiers[z].field]; if (!value) { // console.log(`WARNING: Could not find field '${metric.field}' in report '${report}' for Prometheus metric '${metricName}'. Field could be missing because its value is 0, but make sure field is valid key.`); continue; } if (!isNumeric(value)) { - console.log(`ERROR: Non-numeric error - the field '${metric.field}' in report '${report}' for Prometheus metric '${metricName}' is not numeric.`); + console.log(`ERROR: Non-numeric error - the field '${metric.identifiers[z].field}' in report '${report}' for Prometheus metric '${metricName}' is not numeric.`); continue; } try { (new prometheus.Gauge({ name: name, - help: metric.desc, + help: metric.identifiers[z].desc, labelNames: ['parm'] })).set({ - parm: metric.field + parm: metric.identifiers[z].field }, parseFloat(value)); } catch (err) { //console.log(err); @@ -150,8 +150,8 @@ function getValue (data, metric) { // Check through caption if it exists if (data["caption"]) { for (const key in data["caption"]) { - if (key === metric.field) { - return data["caption"][metric.field]; + if (key === metric.identifiers[z].field) { + return data["caption"][metric.identifiers[z].field]; } } } @@ -166,7 +166,7 @@ function getValue (data, metric) { } } if (passes) { - return entity[metric.field]; + return entity[metric.identifiers[z].field]; } } } From 430e18b159ea97603595a45857084d7f79773e8b Mon Sep 17 00:00:00 2001 From: Salisu Ali Date: Tue, 1 Aug 2023 12:13:27 +0100 Subject: [PATCH 7/7] Multiple Identifier Signed-off-by: Salisu Ali --- src/admin.db | Bin 12288 -> 12288 bytes src/metrics.js | 105 ++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 83 insertions(+), 22 deletions(-) diff --git a/src/admin.db b/src/admin.db index 2a6f0e234d2d902f20de2b8d06d29083c3e32afc..5bc02dafa7f55be16b06f97d68de86fe13f7e70b 100644 GIT binary patch delta 222 zcmZojXh@hK&B!uQ#+i|2V}ie&iF-t(fu(auaIk-FR(6`Ddt^~%V5*-}ptpN~zD0qD zcZ9jGN2Zf`xO-5jW4dc#YE@cA?&Jh{jmg~dvKIa!jwXIp*(SbKPL_Iw0q&)Vc~J!^ z7LhI~X~v-?AtuFvu2o4DrDhgEu8F0&1z8!%l~GCF6}~_N0{s!19g974!%UK$Jdi=ZkBrSPQl4}9!aT{ zF1}@cWvQj<@n)_Oz9I2Ro{r_=rU9N=Ch_@^rd57MzU4pz0{s!1U5h<)!%UK$JKqNUVwk3aj=_Xxp$7Av8AqgV39{qdVZ-}KuTp{wy9~bk#kW+Qn+D$ LMwF@JA_V~epDspm diff --git a/src/metrics.js b/src/metrics.js index d95c38b..96ba59c 100644 --- a/src/metrics.js +++ b/src/metrics.js @@ -37,13 +37,20 @@ setInterval(async () => { for (const lpar of lpars) { // Dynamically get which DDS reports must be made to get data via the metrics var requests = {}; + var multi_true_request = {} for (const metricName in metrics) { var metric = metrics[metricName]; - if (metric.lpar === lpar) { - requests[metric.request.report + " " + (metric.request.resource ? metric.request.resource : dds[lpar]["mvsResource"])] = true; + if(metric.multi === true){ + if (metric.lpar === lpar) { + multi_true_request[metric.request.report + " " + (metric.request.resource ? metric.request.resource : dds[lpar]["mvsResource"])] = true; + } + }else{ + if (metric.lpar === lpar) { + requests[metric.request.report + " " + (metric.request.resource ? metric.request.resource : dds[lpar]["mvsResource"])] = true; + } } } - // Loop through DDS requests + // Loop through DDS requests for single identifier for (const request in requests) { var [ report, resource ] = request.split(" ") // Get XML data from DDS (this method is more efficient than calling our own API with axios) @@ -108,29 +115,83 @@ setInterval(async () => { } } - // Get value of metric - //var value = getValue(result, metric); - // If no match, log error and continue - /* if (!value) { - // console.log(`WARNING: Could not find field '${metric.field}' in report '${report}' for Prometheus metric '${metricName}'. Field could be missing because its value is 0, but make sure field is valid key.`); - continue; - } */ - // If non numeric value is chosen, log error and continue - /* if (!isNumeric(value)) { - console.log(`ERROR: Non-numeric error - the field '${metric.field}' in report '${report}' for Prometheus metric '${metricName}' is not numeric.`); - continue; - } - try{ + } + } + } + } + }) + .catch((err) => { + console.log(err); + }); + } + + // Loop through DDS requests for multiple identifier + for (const request in multi_true_request) { + var [ report, resource ] = request.split(" ") + // Get XML data from DDS (this method is more efficient than calling our own API with axios) + await axios.get(`${use_cert == 'true' ? 'https' : 'http'}://${appurl}:${appport}/v1/${lpar}/rmf3/${report}?resource=${resource}`) + .then((response) => { + // Loop through metrics using this report + const result = response.data; + for (const metricName in metrics) { + var metric = metrics[metricName]; + //Loop through Identifiers + for (var z in metric.identifiers) + { + /* console.log(metric.identifiers[z].id[0].key) + console.log(metric.identifiers[z].id[1].key) + console.log("==================") */ + //Check if users want data from all records in the JSON table having the metrics key + if(metric.identifiers[z].id[0].value === "ALL" && metric.identifiers[z].id[1].value === "ALL"){ + for (i in result['table']) { // loop through the entities + var JSONBody = result['table'][i]; + var name = `${lpar}_${JSONBody[metric.identifiers[z].id[0].key]}_${JSONBody[metric.identifiers[z].id[1].key]}_${metric.identifiers[z].m_id}`; //append TOU(Total Utilization) to lpar name + var value = JSONBody[metric.identifiers[z].field]; + try { (new prometheus.Gauge({ - name: metricName, - help: metric.desc, + name: name, + help: metric.identifiers[z].desc, labelNames: ['parm'] })).set({ - parm: metric.field + parm: metric.identifiers[z].field }, parseFloat(value)); - } catch(err) { - console.log(err); - } */ + } catch (err) { + //console.log(err); + } + } + + }else{ + if (metric.request.report === report && metric.request.resource === resource) { + for (i in result['table']) { // loop through the entities + var JSONBody = result['table'][i]; + //console.log(JSONBody[metric.identifiers[z].id[0].key] == metric.identifiers[z].id[0].value) + if(JSONBody[metric.identifiers[z].id[0].key] == metric.identifiers[z].id[0].value || JSONBody[metric.identifiers[z].id[1].key] == metric.identifiers[z].id[1].value) + { + var name = `${lpar}_${JSONBody[metric.identifiers[z].id[0].key]}_${JSONBody[metric.identifiers[z].id[1].key]}_${metric.identifiers[z].m_id}`; //append TOU(Total Utilization) to lpar name + var value = JSONBody[metric.identifiers[z].field]; + if (!value) { + // console.log(`WARNING: Could not find field '${metric.field}' in report '${report}' for Prometheus metric '${metricName}'. Field could be missing because its value is 0, but make sure field is valid key.`); + continue; + } + if (!isNumeric(value)) { + console.log(`ERROR: Non-numeric error - the field '${metric.identifiers[z].field}' in report '${report}' for Prometheus metric '${metricName}' is not numeric.`); + continue; + } + try { + (new prometheus.Gauge({ + name: name, + help: metric.identifiers[z].desc, + labelNames: ['parm'] + })).set({ + parm: metric.identifiers[z].field + }, parseFloat(value)); + } catch (err) { + console.log(err); + } + break; + } + + } } } }