require([ "/static/app/DA-ITSI-CP-vmware-dashboards/swc-vmware-cp/index.js", "pm/PMLayoutView", "pm/ThresholdCollection", "pm/contrib/d3/d3.amd", "pm/PMPinboardView", "pm/PMTreeView", '/static/app/DA-ITSI-CP-vmware-dashboards/libs/underscore.js', ], function ( SWCVMware, PMLayout, ThresholdCollection, d3, PMPinboard, PMTree, _) { const mvc = SWCVMware.MVC; const DashboardController = SWCVMware.SimpleXML; const HeaderView = SWCVMware.HeaderView; const DropdownInput = SWCVMware.DropdownInput; const utils = SWCVMware.MVCUtils; const FooterView = SWCVMware.FooterView; const TimeRangeInput = SWCVMware.TimerangeInput; const SearchManager = SWCVMware.SearchManager; const PostProcessManager = SWCVMware.PostProcessManager; const SubmitButton = SWCVMware.SubmitInput; const UrlTokenModel = SWCVMware.URLTokenModel; var pageLoading = true; // // TOKENS // // Create token namespaces var urlTokenModel = new UrlTokenModel(); mvc.Components.registerInstance('url', urlTokenModel); var defaultTokenModel = mvc.Components.getInstance('default', {create: true}); var submittedTokenModel = mvc.Components.getInstance('submitted', {create: true}); // Initialize tokens defaultTokenModel.set(urlTokenModel.toJSON()); var defaultUpdate = {}; var submitTokensSoon = _.debounce(function (replaceState) { submittedTokenModel.set(defaultTokenModel.toJSON()); urlTokenModel.saveOnlyWithPrefix('form\\.', defaultTokenModel.toJSON(), { replaceState: replaceState }); }); var submitTokens = function () { submitTokensSoon(pageLoading); }; urlTokenModel.on('url:navigate', function () { defaultTokenModel.set(urlTokenModel.toJSON()); if (!_.isEmpty(urlTokenModel.toJSON()) && !_.all(urlTokenModel.toJSON(), _.isUndefined)) { submitTokens(); } else { submittedTokenModel.clear(); } }); // // SEARCH MANAGERS // // Base Populating search for fields 'field2' and 'field3' var metrics_search = new SearchManager({ "id": "metrics_search", "latest_time": "2", "earliest_time": "1", "search": "| inputlookup VMWPerformanceMetrics", "cancelOnUnload": true, "status_buckets": 0, "app": utils.getCurrentApp(), "auto_cancel": 90, "cache": 6000, "preview": false }, {tokens: true}); // Populating search for field 'field2' var search1 = new PostProcessManager({ "managerid": "metrics_search", "id": "search1", "latest_time": "$latest$", "search": "search entity=$entity_type$ | dedup perftype | table perftype", "earliest_time": "$earliest$", "cancelOnUnload": true, "status_buckets": 0, "app": utils.getCurrentApp(), "auto_cancel": 90, "preview": true }, {tokens: true}); // Populating search for field 'field3' var search2 = new PostProcessManager({ "managerid": "metrics_search", "id": "search2", "latest_time": "$latest$", "search": "search entity=$entity_type$ perftype=$perf_type$ | table metric", "earliest_time": "$earliest$", "cancelOnUnload": true, "status_buckets": 0, "app": utils.getCurrentApp(), "auto_cancel": 90, "preview": true }, {tokens: true}); // // SPLUNK HEADER AND FOOTER // new HeaderView({ id: 'header', section: 'dashboards', el: $('.header'), acceleratedAppNav: true }, {tokens: true}).render(); new FooterView({ id: 'footer', el: $('.footer') }, {tokens: true}).render(); // // VIEWS: FORM INPUTS // var field1 = new DropdownInput({ "id": "field1", "choices": [ {"value": "virtualmachine", "label": "Virtual Machine"}, {"value": "hostsystem", "label": "Host System"} ], "default": "virtualmachine", "seed": "virtualmachine", "value": "$form.entity_type$", "showClearButton": false, "el": $('#field1') }, {tokens: true}).render(); field1.on("change", function (value, input, options) { if (!field1.hasValue()) { defaultUpdate['field1'] = true; this.val(field1.settings.get("default")); return; } var newValue = field1.val() || field1.settings.get("default"); var newComputedValue = newValue; if (newComputedValue === "hostsystem") { var perfSourceValue = "HostSystem"; var metricEntityValue = "esxihost"; }else { var perfSourceValue = "VirtualMachine"; var metricEntityValue = "vm"; } // Update computed value defaultTokenModel.set("metric_entity", metricEntityValue); defaultTokenModel.set("perf_source", perfSourceValue); defaultTokenModel.set("entity_type", newComputedValue); }); defaultUpdate['field1'] = true; field1.trigger("change", field1.val(), field1); var field2 = new DropdownInput({ "id": "field2", "choices": [], "default": "cpu", "seed": "cpu", "labelField": "perftype", "valueField": "perftype", "value": "$form.perf_type$", "showClearButton": false, "managerid": "search1", "el": $('#field2') }, {tokens: true}).render(); field2.on("change", function (value, input, options) { if (!field2.hasValue()) { defaultUpdate['field2'] = true; this.val(field2.settings.get("default")); return; } var newValue = field2.val() || field2.settings.get("default"); var newComputedValue = newValue; if (newValue === "mem") { newValue = "memory" } var newDisplayPerfType = newValue // Update computed value defaultTokenModel.set("perf_type", newComputedValue); defaultTokenModel.set("display_perf_type", newDisplayPerfType); }); defaultUpdate['field2'] = true; field2.trigger("change", field2.val(), field2); var field3 = new DropdownInput({ "id": "field3", "choices": [], "valueField": "metric", "labelField": "metric", "value": "$form.metric$", "managerid": "search2", "showClearButton": false, "el": $('#field3'), "width": 350 // If you change this, change the width in // the corresponding HTML container }, { tokens: true }).render(); field3.on("change", function (value, input, options) { if (!field3.hasValue()) { defaultUpdate['field3'] = true; this.val(field3.settings.get("default")); return; } var newValue = field3.val() || field3.settings.get("default"); var newComputedValue = newValue; var metricPerfComponent = ""; if(newComputedValue){ metricPerfComponent = newComputedValue.split("_"); } var metricAggregationValue = metricPerfComponent[0]; var metricTypeValue = metricPerfComponent[2]; var unitValue = metricPerfComponent[3]; // Update computed value defaultTokenModel.set("metric_aggregation", metricAggregationValue); defaultTokenModel.set("metric_type", metricTypeValue); defaultTokenModel.set("unit", unitValue); defaultTokenModel.set("metric", newComputedValue); }); defaultUpdate['field3'] = true; field3.trigger("change", field3.val(), field3); //$("#field3 .select2-container").first().width(250); var field4 = new TimeRangeInput({ "id": "field4", "default": {"latest_time": "now", "earliest_time": "-24h@h"}, "earliest_time": "$earliest$", "latest_time": "$latest$", "el": $('#field4') }, {tokens: true}).render(); field4.on("change", function (value, input, options) { if (!field4.hasValue()) { defaultUpdate['field4'] = true; field4.updateValueWithDefault(); return; } // Submit the token only if it wasn't from setting the default if (defaultUpdate['field4']) { defaultUpdate['field4'] = false; } else { submitTokens(); } }); defaultUpdate['field4'] = true; field4.trigger("change", field4.val(), field4); // // SUBMIT FORM DATA // var submit = new SubmitButton({ id: 'submit', el: $('#search_btn') }, {tokens: true}).render(); submit.on("submit", function () { //FIXME: make this alerting sexier var field3_val = field3.val(); //In cupcake search results are stored at .visualization._data, in bubbles they are at .select._data, fun right? var viz = field3.select || field3.visualization; if (field3_val === undefined || _.find(viz._data, function (result) { return result.metric === field3_val; }) === undefined) { alert("You must select a metric to kick off performance searches!"); } else { submitTokens(); } }); if (!_.isEmpty(urlTokenModel.toJSON())) { submitTokens(); } // // DASHBOARD READY // DashboardController.ready(); pageLoading = false; //We good to go bro! $("body").removeClass("preload"); // // Proactive Monitoring Render // var main_container = $(".proactive-monitoring-container").first(); // // Layout Creation // var layout = new PMLayout({el: main_container}); layout.render(); // // Threshold Data Bindings // var thresholds = new ThresholdCollection(); //Keep modified threshold data on hand any time it changes (i.e. when it arrives) //FIXME: there is a race condition here if the dynamic tokens are somehow set, may be possible via uri string var submitted_tokens = mvc.Components.get('submitted'); var threshold_data = {}; thresholds.on("sync", function () { threshold_data = this.reduce(function (memo, model) { var entitytype = model.entry.content.attributes.entitytype.toLowerCase(); if (!memo.hasOwnProperty(entitytype)) { memo[entitytype] = {}; } memo[entitytype][model.entry.content.attributes.metric] = model.entry.content.attributes; return memo; }, threshold_data); submitted_tokens.trigger('change:metric'); }, thresholds); thresholds.fetch({ data: { app: "DA-ITSI-CP-vmware-dashboards", search: "p_*", count: "0" } }); //Bind to the change in metric to get our thresholding search proper submitted_tokens.on('change:metric', _.debounce(function () { var cur_metric = submitted_tokens.get("metric"); var entitytype = submitted_tokens.get("entity_type"); var entity_thresholds = threshold_data[entitytype] || {}; if (cur_metric !== null && cur_metric !== undefined && entity_thresholds.hasOwnProperty("p_" + cur_metric)) { var threshold = entity_thresholds["p_" + cur_metric]; var snippet = "eval threshold_severity=case(avg_metric" + threshold.comparator + threshold.critical + ', "critical", avg_metric' + threshold.comparator + threshold.warning + ', "warning", isnotnull(avg_metric), "normal", 1==1, "unknown")'; snippet = snippet + ' | eval threshold_index=case(threshold_severity=="critical", 0, threshold_severity=="warning", 1, threshold_severity=="normal", 2, threshold_severity=="unknown", 3) '; submitted_tokens.set("threshold_snippet", snippet); } else { submitted_tokens.set("threshold_snippet", 'eval threshold_severity="unknown" | eval threshold_index=3'); } })); // // Search Managers // var vm_hierarchy_search = new SearchManager({ id: "virtualmachine-hierarchy", earliest_time: "-8h", latest_time: "now", preview: false, cache: 600, search: '`vmwareinv-index` sourcetype=vmware_inframon:inv:hierarchy earliest=-8h latest=now "\\"type\\": \\"VirtualMachine\\"" OR "\\"type\\": \\"RootFolder\\"" OR "\\"type\\": \\"HostSystem\\"" OR "\\"type\\": \\"ClusterComputeResource\\"" ' + '| spath changeSet.runtime.host.moid output=vmhost ' + '| spath moid output=moid ' + '| spath type output=type ' + '| spath changeSet.name output=name ' + '| search type="HostSystem" OR type="VirtualMachine" OR type="ClusterComputeResource" OR type="RootFolder" ' + '| spath changeSet.parent.moid output=parent ' + '| spath changeSet.parent.type output=parentType ' + '| spath rootFolder.moid output=rootFolderMoid ' + '| eval parent=if(type="VirtualMachine", vmhost, if(parentType="ComputeResource" OR parentType="Folder", rootFolderMoid, parent)) ' + '| eval parentType=if(type="VirtualMachine", "HostSystem", if(parent=rootFolderMoid, "RootFolder", parentType)) ' + '| stats first(name) as name first(type) as type first(parent) as parent first(parentType) as parentType by host, moid ' + '| eval moid=if(type="RootFolder", "*", moid) ' + '| eval parent=if(parentType="RootFolder", "*", parent)', time_format: "%s.%Q" }, {tokens: true, tokenNamespace: "submitted"}); var host_hierarchy_search = new SearchManager({ id: "hostsystem-hierarchy", earliest_time: "-8h", latest_time: "now", preview: false, cache: 600, search: '`vmwareinv-index` sourcetype=vmware_inframon:inv:hierarchy earliest=-8h latest=now "\\"type\\": \\"RootFolder\\"" OR "\\"type\\": \\"HostSystem\\"" OR "\\"type\\": \\"ClusterComputeResource\\"" ' + '| spath moid output=moid ' + '| spath type output=type ' + '| spath changeSet.name output=name ' + '| search type="HostSystem" OR type="ClusterComputeResource" OR type="RootFolder" ' + '| spath changeSet.parent.moid output=parent ' + '| spath changeSet.parent.type output=parentType ' + '| spath rootFolder.moid output=rootFolderMoid ' + '| eval parent=if(parentType="ComputeResource" OR parentType="Folder", rootFolderMoid, parent) ' + '| eval parentType=if(parent=rootFolderMoid, "RootFolder", parentType) ' + '| stats first(name) as name first(type) as type first(parent) as parent first(parentType) as parentType by host, moid ' + '| eval moid=if(type="RootFolder", "*", moid) ' + '| eval parent=if(parentType="RootFolder", "*", parent)', time_format: "%s.%Q" }, {tokens: true, tokenNamespace: "submitted"}); var leaf_performance_search = new SearchManager({ id: "leaf-performance", earliest_time: "$earliest$", latest_time: "$latest$", preview: false, cache: 600, status_buckets: 0, search: '| mstats avg(_value) as avgValue max(_value) as maxValue ' + 'where metric_name=vsphere.$metric_entity$.$perf_type$.$metric_type$ AND `vmwareperf-metrics-index` AND source="VMPerf:$perf_source$" ' + 'AND instance="aggregated" AND unit="$unit$" by vmware_metric_aggregation host moid ' + '| eval avg_$metric_type$_$unit$ =if(vmware_metric_aggregation="$metric_aggregation$",avgValue,NULL) ' + '| eval max_$metric_type$_$unit$ =if(vmware_metric_aggregation="$metric_aggregation$",maxValue,NULL) ' + '| stats avg(avg_$metric_type$_$unit$) AS avg_metric max(max_$metric_type$_$unit$) as max_metric by host, moid ' + '| $threshold_snippet$', time_format: "%s.%Q" }, {tokens: true, tokenNamespace: "submitted"}); var performance_distribution_search = new SearchManager({ id: "leaf-performance-distribution", earliest_time: "$earliest$", latest_time: "$latest$", preview: false, cache: 600, status_buckets: 0, search: '| mstats span=1m median(_value) as medianValue perc25(_value) as perc25Value perc75(_value) as perc75Value ' + 'perc95(_value) as perc95Value min(_value) as minValue ' + 'where metric_name=vsphere.$metric_entity$.$perf_type$.$metric_type$ AND `vmwareperf-metrics-index` AND source="VMPerf:$perf_source$" ' + 'AND instance="aggregated" AND unit="$unit$" by vmware_metric_aggregation ' + '| eval median_$metric_type$_$unit$ =if(vmware_metric_aggregation="$metric_aggregation$",medianValue,NULL) ' + '| eval perc25_$metric_type$_$unit$ =if(vmware_metric_aggregation="$metric_aggregation$",perc25Value,NULL) ' + '| eval perc75_$metric_type$_$unit$ =if(vmware_metric_aggregation="$metric_aggregation$",perc75Value,NULL) ' + '| eval perc95_$metric_type$_$unit$ =if(vmware_metric_aggregation="$metric_aggregation$",perc95Value,NULL) ' + '| eval min_$metric_type$_$unit$ =if(vmware_metric_aggregation="$metric_aggregation$",minValue,NULL) ' + '| timechart minspan=1m median(median_$metric_type$_$unit$) AS center ' + 'perc25(perc25_$metric_type$_$unit$) as lower_quartile ' + 'perc75(perc75_$metric_type$_$unit$) as upper_quartile ' + 'perc95(perc95_$metric_type$_$unit$) as upper_extreme ' + 'min(min_$metric_type$_$unit$) as lower_extreme', time_format: "%s.%Q" }, {tokens: true, tokenNamespace: "submitted"}); /* * Alternate Distribution searches: * BOX AND WHISKER * | `tstats` median($metric$) perc25($metric$) perc75($metric$) perc95($metric$) min($metric$) from vmw_perf_$display_perf_type$_$entity_type$ where instance="aggregated" $metric$>=0 groupby _time span=1m | timechart minspan=1m median($metric$) AS center perc25($metric$) as lower_quartile perc75($metric$) as upper_quartile perc95($metric$) as upper_extreme min($metric$) as lower_extreme * * NORMAL CURVE * | `tstats` avg($metric$) stdev($metric$) from vmw_perf_$display_perf_type$_$entity_type$ where instance="aggregated" $metric$>=0 groupby _time span=1m | timechart minspan=1m avg($metric$) AS avg_metric stdev($metric$) as sigma | eval plus_sigma=avg_metric+sigma | eval plus_2sigma=avg_metric+sigma+sigma | eval minus_sigma=avg_metric-sigma | eval minus_2sigma=avg_metric-sigma-sigma | fields - sigma | rename minus_2sigma AS lower_extreme plus_2sigma AS upper_extreme plus_sigma AS upper_quartile minus_sigma AS lower_quartile avg_metric AS center * */ var specific_performance_search = new SearchManager({ id: "specific-node-performance", earliest_time: "$earliest$", latest_time: "$latest$", preview: false, cache: 600, status_buckets: 0, search: '| mstats span=1m avg(_value) as avgValue where metric_name=vsphere.$metric_entity$.$perf_type$.$metric_type$ AND `vmwareperf-metrics-index` AND source="VMPerf:$perf_source$" ' + 'AND (moid="$tooltip_node$" AND host="$tooltip_tree$") OR (hypervisor="$tooltip_node$" AND host="$tooltip_tree$") OR (cluster="$tooltip_node$" AND host="$tooltip_tree$") ' + 'AND instance="aggregated" AND unit="$unit$" by vmware_metric_aggregation ' + '| eval avg_$metric_type$_$unit$ =if(vmware_metric_aggregation="$metric_aggregation$",avgValue,NULL) ' + '| timechart minspan=1m avg(avg_$metric_type$_$unit$) AS metric', time_format: "%s.%Q" }, {tokens: true, tokenNamespace: "submitted"}); // // Main View Controllers // var pinboard = new PMPinboard({ el: layout.$sidebar }); pinboard.render(); var tree = new PMTree({ el: layout.$main_stage, managerid: "$entity_type$-hierarchy", leaf_type: "$entity_type$", metric: "$metric$", threshold_data: threshold_data, perf_managerid: "leaf-performance", perf_message_container: $("#search_processing_indicator"), tooltip_distribution_managerid: "leaf-performance-distribution", tooltip_specific_managerid: "specific-node-performance", tooltip_tree_token: "$tooltip_tree$", tooltip_node_token: "$tooltip_node$", tooltip_earliest: "$earliest$", tooltip_latest: "$latest$" }, {tokens: true, tokenNamespace: "submitted"}); //Christmas Tree Easter Egg, yes mixing holidays there window.xmasMode = function () { window.mode = 1; return window.setInterval(function () { if (window.mode === 1) { d3.selectAll("circle").attr("opacity", 1); window.mode = 2; } else if (window.mode === 2) { d3.selectAll("circle").each(function (d, i) { if (i % 2 === 0) { d3.select(this).attr("opacity", 1); } else { d3.select(this).attr("opacity", 1e-6); } }); window.mode = 3; } else if (window.mode === 3) { d3.selectAll("circle").each(function (d, i) { if (i % 2 === 1) { d3.select(this).attr("opacity", 1); } else { d3.select(this).attr("opacity", 1e-6); } }); window.mode = 4; } else { d3.selectAll("circle").attr("opacity", 1e-6); window.mode = 1; } }, 500); }; } );