http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/ctrls/overview.js ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/ctrls/overview.js b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/ctrls/overview.js new file mode 100644 index 0000000..6e7df0b --- /dev/null +++ b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/ctrls/overview.js @@ -0,0 +1,298 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function () { + /** + * `register` without params will load the module which using require + */ + register(function (hadoopMetricApp) { + hadoopMetricApp.controller("overviewCtrl", function ($q, $wrapState, $scope, PageConfig, METRIC, Time) { + var cache = {}; + $scope.site = $wrapState.param.siteId; + var activeMasterInfo = METRIC.hbaseMaster($scope.site, "active", 1); + + PageConfig.title = 'HBase'; + var storageOption = { + animation: false, + tooltip: { + formatter: function (points) { + return points[0].name + "<br/>" + + $.map(points, function (point) { + return '<span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:' + point.color + '"></span> ' + + point.seriesName + ": " + + common.number.abbr(point.value, true, 0); + }).reverse().join("<br/>"); + } + }, + yAxis: [{ + axisLabel: { + formatter: function (value) { + return common.number.abbr(value, true); + } + } + }] + }; + + + function generateHbaseMetric(name, flag) { + var startTime = Time.startTime(); + var endTime = Time.endTime(); + var interval = Time.diffInterval(startTime, endTime); + var intervalMin = interval / 1000 / 60; + var trendStartTime = Time.align(startTime, interval); + var trendEndTime = Time.align(endTime, interval); + + $scope.site = $wrapState.param.siteId; + var result = cache[name] || activeMasterInfo._promise.then(function (res) { + var hostname = cache[hostname] = cache[hostname] || res[0].tags.hostname; + $scope.defaultHostname = $wrapState.param.hostname || hostname; + + var jobCond = { + site: $scope.site, + component: "hbasemaster", + host: $scope.defaultHostname + }; + return METRIC.aggMetricsToEntities(METRIC.hbaseMetricsAggregation(jobCond, name, ["site"], "avg(value)", intervalMin, trendStartTime, trendEndTime), flag) + ._promise.then(function (list) { + var metricFlag = $.map(list, function (metrics) { + return metrics[0].flag; + }); + return [metricFlag, list]; + }); + }); + return result; + } + + function mergeMetricToOneSeries(metricTitle, metrics, legendName, dataOption, option) { + var series = []; + + $.each(metrics, function (i, metricMap) { + if (typeof metricMap !== 'undefined') { + series.push(METRIC.metricsToSeries(legendName[i], metricMap[0], option)); + } + }); + return { + title: metricTitle, + series: series, + option: dataOption || {}, + loading: false + }; + } + + function countHBaseRole(site, status, role, groups, filed, limit) { + var jobCond = { + site: site, + status: status, + role: role + }; + return METRIC.aggHBaseInstance(jobCond, groups, filed, limit); + } + + function sumAllRegions(site, role, groups, filed, limit) { + var jobCond = { + site: site, + role: role + }; + return METRIC.aggHBaseInstance(jobCond, groups, filed, limit); + } + + // TODO: Optimize the chart count + // TODO: ECharts dynamic refresh series bug: https://github.com/ecomfe/echarts/issues/4033 + $scope.chartList = [ + { + name: "MemoryUsage", + metrics: ["nonheap", "heap"], + linename: ["nonheap", "heap"], + option: storageOption + }, + { + name: "Master Averageload", + metrics: ["averageload"], + linename: ["averageload"], + option: {} + }, + { + name: "Ritcount", + metrics: ["ritcount", "ritcountoverthreshold"], + linename: ["ritcount", "ritcountoverthreshold"], + option: {} + }, + { + name: "AssignOpsNum", + metrics: ["AssignNumOps"], + linename: ["numOps"], + option: {} + }, + { + name: "Assign", + metrics: ["AssignMin", "AssignMax", "AssignPercentile75th", "AssignPercentile95th", "AssignPercentile99th"], + linename: ["min", "max", "75th", "95th", "99th"], + option: {} + }, + { + name: "BulkAssignOpsNum", + metrics: ["BulkAssignNum_ops"], + linename: ["num_ops"], + option: {} + }, + { + name: "BulkAssign", + metrics: ["BulkAssignMin", "BulkAssignMax", "BulkAssignPercentile75th", "BulkAssignPercentile95th", "BulkAssignPercentile99th"], + linename: ["min", "max", "75th", "95th", "99th"], + option: {} + }, + { + name: "BalancerClusterOpsNum", + metrics: ["BalancerClusterNum_ops"], + linename: ["num_ops"], + option: {} + }, + { + name: "BalancerCluster", + metrics: ["BalancerClusterMin", "BalancerClusterMax", "BalancerClusterPercentile75th", "BalancerClusterPercentile95th", "BalancerClusterPercentile99th"], + linename: ["min", "max", "75th", "95th", "99th"], + option: {} + }, + { + name: "HlogSplitTime", + metrics: ["HlogSplitTimeMin", "HlogSplitTimeMax"], + linename: ["HlogSplitTime_min", "HlogSplitTime_max"], + option: {} + }, + { + name: "HlogSplitTime Percentile", + metrics: ["HlogSplitTimePercentile75th", "HlogSplitTimePercentile95th", "HlogSplitTimePercentile99th"], + linename: ["75th", "95th", "99th"], + option: {} + }, + { + name: "HlogSplitSize", + metrics: ["HlogSplitSizeMin","HlogSplitSizeMax"], + linename: ["Min", "Max"], + option: {} + }, + { + name: "MetaHlogSplitTime", + metrics: ["MetaHlogSplitTimeMin", "MetaHlogSplitTimeMax"], + linename: ["Min", "Max"], + option: {} + }, + { + name: "MetaHlogSplitTime Percentile", + metrics: ["MetaHlogSplitTimePercentile75th", "MetaHlogSplitTimePercentile95th", "MetaHlogSplitTimePercentile99th"], + linename: ["75th", "95th", "99th"], + option: {} + }, + { + name: "MetaHlogSplitSize", + metrics: ["MetaHlogSplitSizeMin", "MetaHlogSplitSizeMax"], + linename: ["Min", "Max"], + option: {} + } + ]; + $scope.metricList = []; + $.each($scope.chartList, function (i) { + var chart = $scope.chartList[i]; + var chartname = chart.name; + $scope.metricList[chartname] = { + title: chartname, + series: {}, + option: {}, + loading: true, + promises: [] + }; + }); + $scope.refresh = function () { + + METRIC.getMetricObj().then(function (res) { + var masterMetricList = res.master; + $.each($scope.chartList, function (i) { + var chart = $scope.chartList[i]; + var metricList = chart.metrics; + $.each(metricList, function (j) { + var metricKey = metricList[j]; + var metricspromies = generateHbaseMetric(masterMetricList[metricKey], metricKey); + var chartname = chart.name; + $scope.metricList[chartname].promises.push(metricspromies); + }); + }); + + $.each($scope.chartList, function (k) { + var chart = $scope.chartList[k]; + var chartname = chart.name; + $q.all($scope.metricList[chartname].promises).then(function (resp) { + var series = []; + for (var r = 0; r < resp.length; r += 1) { + var rs = resp[r][1]; + if (rs.length > 0) { + series.push(rs); + } + } + $scope.metricList[chartname] = mergeMetricToOneSeries(chartname, series, chart.linename, chart.option); + }); + }); + }); + + countHBaseRole($scope.site, "active", "hmaster", ["site"], "count")._promise.then(function (res) { + $.map(res, function (data) { + $scope.hmasteractivenum = data.value[0]; + }); + }); + countHBaseRole($scope.site, "standby", "hmaster", ["site"], "count")._promise.then(function (res) { + $.map(res, function (data) { + $scope.hmasterstandbynum = data.value[0]; + }); + }); + + countHBaseRole($scope.site, "live", "regionserver", ["site"], "count")._promise.then(function (res) { + $.map(res, function (data) { + $scope.regionserverhealtynum = data.value[0]; + }); + }); + countHBaseRole($scope.site, "dead", "regionserver", ["site"], "count")._promise.then(function (res) { + $.map(res, function (data) { + $scope.regionserverunhealtynum = data.value[0]; + }); + }); + sumAllRegions($scope.site, "regionserver", ["site"], "sum(numRegions)")._promise.then(function (res) { + $.map(res, function (data) { + $scope.regionsnum = data.value[0]; + }); + }); + + activeMasterInfo._promise.then(function (res) { + var hostname = cache[hostname] = cache[hostname] || res[0].tags.hostname; + $scope.defaultHostname = $wrapState.param.hostname || hostname; + var jobCond = { + site: $scope.site, + component: "hbasemaster", + host: $scope.defaultHostname + }; + METRIC.hbaseMomentMetric(jobCond, "hadoop.hbase.master.server.averageload", 1).then(function (res) { + $scope.hmasteraverageload = (typeof res.data.obj[0] !== 'undefined') ? res.data.obj[0].value[0] : "-1"; + }); + }); + }; + Time.onReload(function () { + cache = {}; + $scope.refresh(); + }, $scope); + $scope.refresh(); + }); + }); +})();
http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/ctrls/regionDetailCtrl.js ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/ctrls/regionDetailCtrl.js b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/ctrls/regionDetailCtrl.js new file mode 100644 index 0000000..838b3a2 --- /dev/null +++ b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/ctrls/regionDetailCtrl.js @@ -0,0 +1,306 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function () { + /** + * `register` without params will load the module which using require + */ + register(function (hadoopMetricApp) { + hadoopMetricApp.controller("regionDetailCtrl", function ($q, $wrapState, $scope, PageConfig, Time, METRIC) { + var cache = {}; + $scope.site = $wrapState.param.siteId; + $scope.hostname = $wrapState.param.hostname; + PageConfig.title = 'RegionServer ' + "(" + $scope.hostname + ")"; + Time.autoRefresh = false; + + var sizeoption = { + animation: false, + tooltip: { + formatter: function (points) { + return points[0].name + "<br/>" + + $.map(points, function (point) { + return '<span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:' + point.color + '"></span> ' + + point.seriesName + ": " + + common.number.abbr(point.value, true); + }).reverse().join("<br/>"); + } + }, + legend: { + x: 'center', y: 'bottom' + }, + areaStyle: {normal: {}}, + yAxis: [{ + axisLabel: { + formatter: function (value) { + return common.number.abbr(value, true); + } + } + }] + }; + var digitalOption = { + animation: false, + tooltip: { + formatter: function (points) { + return points[0].name + "<br/>" + + $.map(points, function (point) { + return '<span style="display:inline-block;margin-right:5px;border-radius:10px;width:9px;height:9px;background-color:' + point.color + '"></span> ' + + point.seriesName + ": " + + common.number.abbr(point.value, false, 0); + }).reverse().join("<br/>"); + } + }, + yAxis: [{ + axisLabel: { + formatter: function (value) { + return common.number.abbr(value, false); + } + } + }] + }; + + var gctimeoption = { + legend: { + x: 'center', y: 'bottom' + }, + yAxis: [{ + axisLabel: { + formatter: function (value) { + return value / 1000 + ' S'; + } + } + }] + }; + $scope.chartList = [ + { + name: "Memory Usage", + metrics: ["nonheap", "heap"], + option: sizeoption + }, + { + name: "Direct Memory Usage", + metrics: ["directmemory"], + option: sizeoption + }, + { + name: "GC count", + metrics: ["GCCount"], + option: {} + }, + { + name: "GC TimeMillis", + metrics: ["GCTimeMillis"], + option: gctimeoption + }, + { + name: "QueueSize", + metrics: ["QueueSize"], + option: {} + }, + { + name: "NumCallsInGeneralQueue", + metrics: ["NumCallsInGeneralQueue"], + option: {} + }, + { + name: "NumActiveHandler", + metrics: ["NumActiveHandler"], + option: {} + }, + { + name: "IPC Queue Time (99th)", + metrics: ["IPCQueueTime99th"], + option: {} + }, + { + name: "IPC Process Time (99th)", + metrics: ["IPCProcessTime99th"], + option: {} + }, + { + name: "QueueCallTime_num_ops", + metrics: ["QueueCallTime_num_ops"], + option: digitalOption + }, + { + name: "ProcessCallTime_num_ops", + metrics: ["ProcessCallTime_num_ops"], + option: digitalOption + }, + { + name: "RegionCount", + metrics: ["RegionCount"], + option: {} + }, + { + name: "StoreCount", + metrics: ["StoreCount"], + option: {} + }, + { + name: "MemStoreSize", + metrics: ["MemStoreSize"], + option: sizeoption + }, + { + name: "StoreFileSize", + metrics: ["StoreFileSize"], + option: sizeoption + }, + { + name: "SlitQueueLength", + metrics: ["SlitQueueLength"], + option: {} + }, + { + name: "CompactionQueueLength", + metrics: ["CompactionQueueLength"], + option: {} + }, + { + name: "FlushQueueLength", + metrics: ["FlushQueueLength"], + option: {} + }, + { + name: "BlockCacheSize", + metrics: ["BlockCacheSize"], + option: sizeoption + }, + { + name: "BlockCacheHitCount", + metrics: ["BlockCacheHitCount"], + option: {} + }, + { + name: "BlockCacheCountHitPercent", + metrics: ["BlockCacheCountHitPercent"], + option: digitalOption + }, + { + name: "TotalRequestCount", + metrics: ["TotalRequestCount"], + option: digitalOption + }, + { + name: "ReadRequestCount", + metrics: ["ReadRequestCount"], + option: digitalOption + }, + { + name: "WriteRequestCount", + metrics: ["WriteRequestCount"], + option: digitalOption + } + ]; + + $scope.metricList = []; + $.each($scope.chartList, function (i) { + var chart = $scope.chartList[i]; + var chartname = chart.name; + $scope.metricList[chartname] = { + title: chartname, + series: {}, + option: {}, + loading: true, + promises: [] + }; + }); + $scope.refresh = function () { + var startTime = Time.startTime(); + var endTime = Time.endTime(); + + METRIC.getMetricObj().then(function (res) { + var masterMetricList = res.regionserver; + $.each($scope.chartList, function (i) { + var chart = $scope.chartList[i]; + var metricList = chart.metrics; + $.each(metricList, function (j) { + var metricKey = metricList[j]; + var metricspromies = generateHbaseMetric(masterMetricList[metricKey], startTime, endTime, metricKey); + var chartname = chart.name; + $scope.metricList[chartname].promises.push(metricspromies); + }); + }); + + $.each($scope.chartList, function (k) { + var chart = $scope.chartList[k]; + var chartname = chart.name; + $q.all($scope.metricList[chartname].promises).then(function (resp) { + var series = []; + for (var r = 0; r < resp.length; r += 1) { + var rs = resp[r][1]; + if (rs.length > 0) { + series.push(rs); + } + } + $scope.metricList[chartname] = mergeSeries(chartname, series, chart.metrics, chart.option); + }); + }); + }); + + METRIC.regionserverStatus($scope.hostname, $scope.site)._promise.then(function (res) { + $scope.regionstatus = res; + }); + }; + Time.onReload(function () { + cache = {}; + $scope.refresh(); + }, $scope); + $scope.refresh(); + + + function generateHbaseMetric(name, startTime, endTime, flag) { + var interval = Time.diffInterval(startTime, endTime); + var intervalMin = interval / 1000 / 60; + var trendStartTime = Time.align(startTime, interval); + var trendEndTime = Time.align(endTime, interval); + + var condition = { + site: $scope.site, + component: "regionserver", + host: $scope.hostname + }; + return METRIC.aggMetricsToEntities(METRIC.hbaseMetricsAggregation(condition, name, ["site"], "avg(value)", intervalMin, trendStartTime, trendEndTime), flag) + ._promise.then(function (list) { + var metricFlag = $.map(list, function (metrics) { + return metrics[0].flag; + }); + return [metricFlag, list]; + }); + } + + function mergeSeries(title, metrics, linename, option) { + var series = []; + $.each(metrics, function (i, metricMap) { + $.map(metricMap, function (metric) { + if (typeof metric !== 'undefined') { + series.push(METRIC.metricsToSeries(linename[i], metric, option)); + } + }); + }); + return { + title: title, + series: series, + option: option || {}, + loading: false + }; + } + }); + }); +}) +(); http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/ctrls/regionListCtrl.js ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/ctrls/regionListCtrl.js b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/ctrls/regionListCtrl.js new file mode 100644 index 0000000..1477e32 --- /dev/null +++ b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/ctrls/regionListCtrl.js @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function () { + /** + * `register` without params will load the module which using require + */ + register(function (hadoopMetricApp) { + + hadoopMetricApp.controller("regionListCtrl", function ($wrapState, $scope, PageConfig, METRIC) { + + // Initialization + PageConfig.title = "HBASE RegionServers"; + $scope.tableScope = {}; + $scope.live = METRIC.STATUS_LIVE; + $scope.dead = METRIC.STATUS_DEAD; + $scope.site = $wrapState.param.siteId; + $scope.searchPathList = [["tags", "hostname"], ["tags", "rack"], ["tags", "site"], ["status"]]; + $scope.regionserverList = METRIC.regionserverList($scope.site); + + }); + }); +})(); http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/index.html ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/index.html b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/index.html new file mode 100644 index 0000000..454e3c6 --- /dev/null +++ b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/index.html @@ -0,0 +1,6 @@ +<htm> + <body> + <h1>HBase Metric Monitor Application!</h1> + <i><b>url</b>: /apps/hbase</i> + </body> +</htm> http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/index.js ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/index.js b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/index.js new file mode 100644 index 0000000..c6b5135 --- /dev/null +++ b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/index.js @@ -0,0 +1,329 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function () { + /** + * `register` is global function that for application to set up 'controller', 'service', 'directive', 'route' in Eagle + */ + var hadoopMetricApp = register(['ngRoute', 'ngAnimate', 'ui.router', 'eagle.service']); + + hadoopMetricApp.route("HBaseMetric", { + url: "/hadoopService/HBase/overview?startTime&endTime", + site: true, + templateUrl: "partials/overview.html", + controller: "overviewCtrl", + resolve: {time: true} + }).route("regionDetail", { + url: "/hadoopService/HBase/regionDetail/:hostname", + site: true, + templateUrl: "partials/region/regionDetail.html", + controller: "regionDetailCtrl", + resolve: {time: true} + }).route("regionList", { + url: "/hadoopService/HBase/regionList", + site: true, + templateUrl: "partials/region/regionList.html", + controller: "regionListCtrl" + }).route("backupMasterList", { + url: "/hadoopService/HBase/backupMasterList", + site: true, + templateUrl: "partials/backupMasterList.html", + controller: "backupMasterListCtrl" + }).route("masterDetail", { + url: "/hadoopService/HBase/:hostname?startTime&endTime", + site: true, + reloadOnSearch: false, + templateUrl: "partials/overview.html", + controller: "overviewCtrl", + resolve: {time: true} + }); + + hadoopMetricApp.portal({ + name: "Services", icon: "heartbeat", list: [ + {name: "HBase", path: "hadoopService/HBase/overview"} + ] + }, true); + + hadoopMetricApp.service("METRIC", function ($q, $http, Time, Site, Application) { + var METRIC = window._METRIC = {}; + METRIC.STATUS_LIVE = "live"; + METRIC.STATUS_DEAD = "dead"; + METRIC.QUERY_HBASE_METRICS = '${baseURL}/rest/entities?query=GenericMetricService[${condition}]{*}&metricName=${metric}&pageSize=${limit}'; + METRIC.QUERY_HBASE_METRICS_WITHTIME = '${baseURL}/rest/entities?query=GenericMetricService[${condition}]{*}&metricName=${metric}&pageSize=${limit}&startTime=${startTime}&endTime=${endTime}'; + METRIC.QUERY_HBASE_INSTANCE = '${baseURL}/rest/entities?query=HbaseServiceInstance[${condition}]{*}&pageSize=${limit}'; + METRIC.QUERY_HBASE_INSTANCE_AGG = "${baseURL}/rest/entities?query=HbaseServiceInstance[${condition}]<${groups}>{${field}}&pageSize=${limit}"; + METRIC.QUERY_HBASE_METRICS_INTERVAL = '${baseURL}/rest/entities?query=GenericMetricService[${condition}]<${groups}>{${field}}${order}${top}&metricName=${metric}&pageSize=${limit}&startTime=${startTime}&endTime=${endTime}&intervalmin=${intervalMin}&timeSeries=true'; + /** + * Fetch query content with current site application configuration + * @param {string} queryName + */ + var getQuery = METRIC.getQuery = function (queryName, siteId) { + var baseURL; + siteId = siteId || Site.current().siteId; + var app = Application.find("HBASE_METRIC_WEB_APP", siteId)[0]; + var host = app.configuration["service.host"]; + var port = app.configuration["service.port"]; + + if (!host && !port) { + baseURL = ""; + } else { + if (host === "localhost" || !host) { + host = location.hostname; + } + if (!port) { + port = location.port; + } + baseURL = "http://" + host + ":" + port; + } + + return common.template(METRIC["QUERY_" + queryName], {baseURL: baseURL}); + }; + + function wrapList(promise) { + var _list = []; + _list._done = false; + + _list._promise = promise.then( + /** + * @param {{}} res + * @param {{}} res.data + * @param {{}} res.data.obj + */ + function (res) { + _list.splice(0); + Array.prototype.push.apply(_list, res.data.obj); + _list._done = true; + return _list; + }); + return _list; + } + + function toFields(fields) { + return (fields || []).length > 0 ? $.map(fields, function (field) { + return "@" + field; + }).join(",") : "*"; + } + + METRIC.metricsToSeries = function (name, metrics, option, rawData) { + if (arguments.length === 4 && typeof rawData === "object") { + option = rawData; + rawData = false; + } + + var data = $.map(metrics, function (metric) { + return rawData ? metric.value[0] : { + x: metric.timestamp, + y: metric.value[0] + }; + }); + return $.extend({ + name: name, + showSymbol: false, + type: "line", + data: data + }, option || {}); + }; + + METRIC.get = function (url, params) { + return $http({ + url: url, + method: "GET", + params: params + }); + }; + + METRIC.condition = function (condition) { + return $.map(condition, function (value, key) { + return "@" + key + '="' + value + '"'; + }).join(" AND "); + }; + + + METRIC.hbaseMetrics = function (condition, metric, startTime, endTime, limit) { + var config = { + condition: METRIC.condition(condition), + startTime: Time.format(startTime), + endTime: Time.format(endTime), + metric: metric, + limit: limit || 10000 + }; + + var metrics_url = common.template(getQuery("HBASE_METRICS_WITHTIME"), config); + return wrapList(METRIC.get(metrics_url)); + }; + + METRIC.hbaseMomentMetric = function (condition, metric, limit) { + var config = { + condition: METRIC.condition(condition), + metric: metric, + limit: limit || 10000 + }; + + var metrics_url = common.template(getQuery("HBASE_METRICS"), config); + return METRIC.get(metrics_url); + }; + + METRIC.aggHBaseInstance = function (condition, groups, field, limit) { + var fields = field.split(/\s*,\s*/); + var fieldStr = $.map(fields, function (field, index) { + var matches = field.match(/^([^\s]*)(\s+.*)?$/); + if (matches[2]) { + orderId = index; + } + return matches[1]; + }).join(", "); + var config = { + condition: METRIC.condition(condition), + groups: toFields(groups), + field: fieldStr, + limit: limit || 10000 + }; + var metrics_url = common.template(getQuery("HBASE_INSTANCE_AGG"), config); + return wrapList(METRIC.get(metrics_url)); + }; + + METRIC.hbaseMetricsAggregation = function (condition, metric, groups, field, intervalMin, startTime, endTime, top, limit) { + var fields = field.split(/\s*,\s*/); + var orderId = -1; + var fieldStr = $.map(fields, function (field, index) { + var matches = field.match(/^([^\s]*)(\s+.*)?$/); + if (matches[2]) { + orderId = index; + } + return matches[1]; + }).join(", "); + + + var config = { + condition: METRIC.condition(condition), + startTime: Time.format(startTime), + endTime: Time.format(endTime), + metric: metric, + groups: toFields(groups), + field: fieldStr, + order: orderId === -1 ? "" : ".{" + fields[orderId] + "}", + top: top ? "&top=" + top : "", + intervalMin: intervalMin, + limit: limit || 10000 + }; + + var metrics_url = common.template(getQuery("HBASE_METRICS_INTERVAL"), config); + var _list = wrapList(METRIC.get(metrics_url)); + _list._aggInfo = { + groups: groups, + startTime: Time(startTime).valueOf(), + interval: intervalMin * 60 * 1000 + }; + _list._promise.then(function () { + _list.reverse(); + }); + return _list; + }; + + METRIC.aggMetricsToEntities = function (list, param, flatten) { + var _list = []; + _list.done = false; + _list._promise = list._promise.then(function () { + var _startTime = list._aggInfo.startTime; + var _interval = list._aggInfo.interval; + + $.each(list, function (i, obj) { + var tags = {}; + $.each(list._aggInfo.groups, function (j, group) { + tags[group] = obj.key[j]; + }); + + var _subList = $.map(obj.value[0], function (value, index) { + return { + timestamp: _startTime + index * _interval, + value: [value], + tags: tags, + flag: param + }; + }); + + if (flatten) { + _list.push.apply(_list, _subList); + } else { + _list.push(_subList); + } + }); + _list.done = true; + return _list; + }); + return _list; + }; + + + METRIC.hbasehostStatus = function (condition, limit) { + var config = { + condition: METRIC.condition(condition), + limit: limit || 10000 + }; + + var metrics_url = common.template(getQuery("HBASE_INSTANCE"), config); + return wrapList(METRIC.get(metrics_url)); + }; + + METRIC.hbaseMaster = function (siteId, status, limit) { + var condition = { + site: siteId, + role: "hmaster", + status: status + }; + return METRIC.hbasehostStatus(condition, limit); + }; + + METRIC.regionserverStatus = function (hostname, siteid) { + var hoststateinfo; + var condition = { + site: siteid, + role: "regionserver", + hostname: hostname + }; + hoststateinfo = METRIC.hbasehostStatus(condition, 1); + return hoststateinfo; + }; + + METRIC.regionserverList = function (siteid) { + var hoststateinfos; + var condition = { + site: siteid, + role: "regionserver" + }; + hoststateinfos = METRIC.hbasehostStatus(condition); + return hoststateinfos; + }; + + METRIC.getMetricObj = function () { + var deferred = $q.defer(); + $http.get("apps/hbase/config.json").success(function (resp) { + deferred.resolve(resp); + }); + return deferred.promise; + }; + return METRIC; + }); + + hadoopMetricApp.requireCSS("style/index.css"); + hadoopMetricApp.require("widgets/availabilityChart.js"); + hadoopMetricApp.require("ctrls/overview.js"); + hadoopMetricApp.require("ctrls/regionDetailCtrl.js"); + hadoopMetricApp.require("ctrls/regionListCtrl.js"); + hadoopMetricApp.require("ctrls/backupMasterListCtrl.js"); +})(); http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/backupMasterList.html ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/backupMasterList.html b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/backupMasterList.html new file mode 100644 index 0000000..13e20c9 --- /dev/null +++ b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/backupMasterList.html @@ -0,0 +1,52 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<div class="box box-primary"> + <div class="box-header with-border"> + <h3 class="box-title"> + <span ng-show="!backupMasterList._done || isSorting" class="fa fa-refresh fa-spin no-animate"></span> + </h3> + </div> + <div class="box-body"> + <div id="backupMasterList" sort-table="backupMasterList" is-sorting="isSorting" + search-path-list="searchPathList" + scope="tableScope"> + <table class="table table-bordered"> + <thead> + <tr> + <th sortpath="tags.hostname">Master</th> + <th sortpath="tags.rack">Rack</th> + <th sortpath="tags.site">SiteId</th> + <th sortpath="status">Status</th> + </tr> + </thead> + <tbody> + <tr ng-repeat="item in backupMasterList"> + <td> + <a ui-sref="masterDetail({siteId: site, hostname: item.tags.hostname})">{{item.tags.hostname}}</a> + </td> + <td>{{item.tags.rack}}</td> + <td>{{item.tags.site}}</td> + <td> + <span>{{item.status}}</span> + </td> + </tr> + </tbody> + </table> + </div> + </div> +</div> http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/overview.html ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/overview.html b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/overview.html new file mode 100644 index 0000000..0e194ef --- /dev/null +++ b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/overview.html @@ -0,0 +1,111 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<div class="box box-primary"> + <div class="box-header with-border"> + <span class="fa fa-television"></span> + <h3 class="box-title"> + HBase Service Summary Information + </h3> + </div> + <div class="box-body"> + <table class="table table-striped hadoopMetric-table"> + <tr> + <td width="5%"> + <span ng-show="hmasteractivenum">{{hmasteractivenum}}</span> + <span ng-show="!hmasteractivenum">N/A</span> + </td> + <th width="45%">Active HBase Master</th> + <td width="5%"> + <span ng-show="regionsnum">{{regionsnum}}</span> + <span ng-show="!regionsnum">N/A</span> + </td> + <th width="45%">Regions + </th> + </tr> + <tr> + <td> + <a ui-sref="backupMasterList({siteId: site})"> + <span ng-show="hmasterstandbynum">{{hmasterstandbynum}}</span></a> + <span ng-show="!hmasterstandbynum">0</span> + </td> + <th>Backup HBase Master</th> + <td> + <span ng-show="hmasteraverageload !== '-1'">{{common.number.format(hmasteraverageload, 0)}}</span> + <span ng-show="hmasteraverageload === '-1'">N/A</span> + </td> + <th>Average Load</th> + </tr> + <tr> + <td> + <a ui-sref="regionList({siteId: site})"> + <span ng-show="regionserverhealtynum || regionserverunhealtynum">{{regionserverhealtynum+regionserverunhealtynum}}</span></a> + <span ng-show="!regionserverhealtynum && !regionserverunhealtynum">N/A</span> + </td> + <th>RegionServers: + <a ui-sref="regionList({siteId: site})"> + <span ng-show="regionserverhealtynum">{{regionserverhealtynum}}</span></a> + <span ng-show="!regionserverhealtynum">0</span> + <span + class="label label-success">Good Health</span> / + <a ui-sref="regionList({siteId: site})"> + <span ng-show="regionserverunhealtynum">{{regionserverunhealtynum}}</span></a> + <span ng-show="!regionserverunhealtynum">0</span> + <span class="label label-danger">Bad Health</span> + </th> + <td></td> + <th></th> + </tr> + </table> + </div> +</div> + +<div class="box box-primary"> + <div class="box-header with-border"> + <span class="fa fa-line-chart"></span> + <h3 class="box-title"> + Metrics + <span>({{defaultHostname}})</span> + </h3> + </div> + <div class="box-body no-padding"> + <div class="row border-split"> + <div class="col-sm-6 col-md-4 col-lg-6" ng-repeat="chart in chartList track by $index"> + <div class="hadoopMetric-chart"> + <h3>{{metricList[chart.name].title}}</h3> + <div ng-show="metricList[chart.name].loading" chart class="hadoopMetric-chart-container"></div> + <div ng-show="metricList[chart.name].loading" class="overlay-wrapper"> + <div class="overlay"> + <i class="fa fa-refresh fa-spin"></i> + </div> + </div> + <div ng-show="metricList[chart.name].series.length" chart class="hadoopMetric-chart-container" + series="metricList[chart.name].series" + option="metricList[chart.name].option"></div> + <div ng-show="!metricList[chart.name].series.length && !metricList[chart.name].loading" class="hadoopMetric-chart-container"> + <div class="hadoopMetric-chart-container-withborder"> + <div class="hadoopMetric-no-chart-data"> + <span class="fa fa-question-circle"></span><span> NO DATA</span> + </div> + </div> + </div> + </div> + </div> + </div> + </div> +</div> http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/region/regionDetail.html ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/region/regionDetail.html b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/region/regionDetail.html new file mode 100644 index 0000000..63a895f --- /dev/null +++ b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/region/regionDetail.html @@ -0,0 +1,117 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +<div class="box box-primary"> + <div class="box-header with-border"> + <span class="fa fa-television"></span> + <h3 class="box-title"> + Summary + </h3> + </div> + <div class="box-body"> + <table class="table table-striped"> + <tbody ng-if="(regionstatus || []).length !== 0"> + <tr> + <th>Status</th> + <td class="text-break"> + <span ng-if="regionstatus[0].status==='live'" class="label label-success">Healthy</span> + <span ng-if="regionstatus[0].status!=='live'" class="label label-danger">UnHealthy</span> + </td> + </tr> + <tr> + <th>Rack</th> + <td class="text-break">{{regionstatus[0].tags.rack}}</td> + </tr> + <tr> + <th>MaxHeap</th> + <td class="text-break">{{regionstatus[0].maxHeapMB}} MB</td> + </tr> + <tr> + <th>UsedHeap</th> + <td class="text-break">{{regionstatus[0].usedHeapMB}} MB</td> + </tr> + <tr> + <th>NumRegions</th> + <td class="text-break">{{regionstatus[0].numRegions}}</td> + </tr> + <tr> + <th>NumRequests</th> + <td class="text-break">{{regionstatus[0].numRequests}}</td> + </tr> + </tbody> + <tbody ng-if="regionstatus.length === 0"> + <tr> + <th>Status</th> + <td class="text-break"><span class="label label-danger">Unknow</span></td> + </tr> + <tr> + <th>Rack</th> + <td class="text-break"><span class="label label-danger">Unknow</span></td> + </tr> + <tr> + <th>MaxHeap</th> + <td class="text-break"><span class="label label-danger">Unknow</span></td> + </tr> + <tr> + <th>UsedHeap</th> + <td class="text-break"><span class="label label-danger">Unknow</span></td> + </tr> + <tr> + <th>NumRegions</th> + <td class="text-break"><span class="label label-danger">Unknow</span></td> + </tr> + <tr> + <th>NumRequests</th> + <td class="text-break"><span class="label label-danger">Unknow</span></td> + </tr> + </tbody> + </table> + </div> +</div> + +<div class="box box-primary"> + <div class="box-header with-border"> + <span class="fa fa-line-chart"></span> + <h3 class="box-title"> + Metrics + </h3> + </div> + <div class="box-body no-padding"> + <div class="row border-split"> + <div class="col-sm-6 hadoopMetric-col-md-6 col-lg-6" ng-repeat="chart in chartList track by $index"> + <div class="hadoopMetric-chart"> + <h3>{{metricList[chart.name].title}}</h3> + <div ng-show="metricList[chart.name].loading" class="hadoopMetric-chart-container"></div> + <div ng-show="metricList[chart.name].loading" class="overlay-wrapper"> + <div class="overlay"> + <i class="fa fa-refresh fa-spin"></i> + </div> + </div> + <div ng-show="metricList[chart.name].series.length" chart class="hadoopMetric-chart-container" + series="metricList[chart.name].series" + option="metricList[chart.name].option"></div> + <div ng-show="!metricList[chart.name].series.length && !metricList[chart.name].loading" class="hadoopMetric-chart-container"> + <div class="hadoopMetric-no-chart-data"> + <span class="fa fa-question-circle"></span><span> NO DATA</span> + </div> + </div> + </div> + </div> + </div> + </div> +</div> http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/region/regionList.html ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/region/regionList.html b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/region/regionList.html new file mode 100644 index 0000000..d1a7440 --- /dev/null +++ b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/partials/region/regionList.html @@ -0,0 +1,53 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> +<div class="box box-primary"> + <div class="box-header with-border"> + <h3 class="box-title"> + <span ng-show="!regionserverList._done || isSorting" class="fa fa-refresh fa-spin no-animate"></span> + </h3> + </div> + <div class="box-body"> + <div id="regionserverList" sort-table="regionserverList" is-sorting="isSorting" + search-path-list="searchPathList" + scope="tableScope"> + <table class="table table-bordered"> + <thead> + <tr> + <th sortpath="tags.hostname">RegionServer</th> + <th sortpath="tags.rack">Rack</th> + <th sortpath="tags.site">SiteId</th> + <th sortpath="status">Status</th> + </tr> + </thead> + <tbody> + <tr ng-repeat="item in regionserverList"> + <td> + <a ui-sref="regionDetail({siteId: site, hostname: item.tags.hostname})">{{item.tags.hostname}}</a> + </td> + <td>{{item.tags.rack}}</td> + <td>{{item.tags.site}}</td> + <td> + <span ng-if="item.status===live" class="label label-success">Healthy</span> + <span ng-if="item.status===dead" class="label label-danger">UnHealthy</span> + </td> + </tr> + </tbody> + </table> + </div> + </div> +</div> http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/style/index.css ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/style/index.css b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/style/index.css new file mode 100644 index 0000000..aa215ab --- /dev/null +++ b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/style/index.css @@ -0,0 +1,88 @@ +@CHARSET "UTF-8"; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.hadoopMetric-chart { + position: relative; + margin-bottom: 15px; +} + +.hadoopMetric-chart h3 { + font-size: 20px; + margin: 10px 0 0 0; +} + +.hadoopMetric-chart .hadoopMetric-chart-container { + height: 300px; + position: relative; +} + +.hadoopMetric-chart .hadoopMetric-no-chart-data { + position:absolute; + left: 38%; + top: 40%; + font-size: 20px; + color: #999; +} + +.with-border .hadoopMetric-chart { + padding-bottom: 15px; + margin-bottom: 15px; + border-bottom: 1px solid #f4f4f4; +} + +.with-border .hadoopMetric-chart:last-child { + padding-bottom: 0; + margin-bottom: 0; + border-bottom: 0; +} + +.hadoopMetric-widget { + width: 100%; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1); + border-radius: 2px; + padding: 10px; +} + +.hadoopMetric-widget h3 { + margin: 0; + padding: 0; +} + +.hadoopMetric-widget .hadoopMetric-chart-container { + height: 100px; +} + +.hadoopMetric-summary-a { + color: #fff; +} + +.small-box.hadoopMetric-widget { + margin: 0; + height: 100%; + min-height: 110px; +} + +.hadoopMetric-widget-detail { + margin-left: 12px; + margin-top: 10px; +} + +.hadoopMetric-table { + text-align: right; +} http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/widgets/availabilityChart.js ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/widgets/availabilityChart.js b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/widgets/availabilityChart.js new file mode 100644 index 0000000..bd0a278 --- /dev/null +++ b/eagle-metric/eagle-hbase-web/src/main/webapp/app/apps/hbase/widgets/availabilityChart.js @@ -0,0 +1,145 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function () { + /** + * `register` without params will load the module which using require + */ + register(function (hadoopMetricApp) { + var COLOR_MAPPING = { + HDFS: 'orange', + HBase: 'yellow', + Yarn: 'green' + }; + + hadoopMetricApp.directive("hadoopMetricWidget", function () { + return { + restrict: 'AE', + controller: function ($scope, $attrs, METRIC, Application, $interval, Site, $wrapState) { + // Get site + var site = $scope.site; + var refreshInterval; + + if(!site) { + $scope.list = $.map(Application.find("HADOOP_METRIC_MONITOR"), function (app) { + return { + siteId: app.site.siteId, + siteName: app.site.siteName || app.site.siteId + }; + }); + } else { + $scope.list = [{ + siteId: site.siteId, + siteName: site.siteName || site.siteId + }]; + } + // Get type + $scope.type = $attrs.type; + + // Customize chart color + $scope.bgColor = COLOR_MAPPING[$scope.type]; + + function countHBaseRole(site, status, role, groups, filed, limit) { + var jobCond = { + site: site, + status: status, + role: role + }; + return METRIC.aggHBaseInstance(jobCond, groups, filed, limit); + } + + // Ref: jpm widget if need keep refresh the widget + + function refresh() { + $.each($scope.list, function (i, site) { + + countHBaseRole(site.siteId, "active", "hmaster", ["site"], "count")._promise.then(function (res) { + $.map(res, function (data) { + $scope.hmasteractivenum = data.value[0]; + }); + }); + countHBaseRole(site.siteId, "standby", "hmaster", ["site"], "count")._promise.then(function (res) { + $.map(res, function (data) { + $scope.hmasterstandbynum = data.value[0]; + }); + }); + countHBaseRole(site.siteId, "live", "regionserver", ["site"], "count")._promise.then(function (res) { + $.map(res, function (data) { + $scope.regionserverhealtynum = data.value[0]; + }); + }); + countHBaseRole(site.siteId, "dead", "regionserver", ["site"], "count")._promise.then(function (res) { + $.map(res, function (data) { + $scope.regionserverunhealtynum = data.value[0]; + }); + }); + }); + } + + refresh(); + refreshInterval = $interval(refresh, 30 * 1000); + + $scope.$on('$destroy', function () { + $interval.cancel(refreshInterval); + }); + }, + template: + '<div class="small-box hadoopMetric-widget bg-{{bgColor}}">' + + '<div class="inner">' + + '<h3>{{type}}</h3>' + + '<div ng-show="hmasteractivenum" class="hadoopMetric-widget-detail">' + + '<a ui-sref="HBaseMetric({siteId: site.siteId})">' + + '<span>{{hmasteractivenum+hmasterstandbynum}}</span> Masters (' + + '<span ng-show="hmasteractivenum">{{hmasteractivenum}}</span><span ng-show="!hmasteractivenum">0</span> Active / ' + + '<span ng-show="hmasterstandbynum">{{hmasterstandbynum}}</span><span ng-show="!hmasterstandbynum">0</span> Standby)' + + '</a>' + + '</div>' + + '<div ng-show="!hmasteractivenum" class="hadoopMetric-widget-detail">' + + '<span class="fa fa-question-circle"></span><span> NO DATA</span>' + + '</div>' + + '<div ng-show="hmasteractivenum" class="hadoopMetric-widget-detail">' + + '<a ui-sref="regionList({siteId: site.siteId})">' + + '<span>{{regionserverhealtynum+regionserverunhealtynum}}</span> RegionServers (' + + '<span ng-show="regionserverhealtynum">{{regionserverhealtynum}}</span><span ng-show="!regionserverhealtynum">0</span> Healthy / ' + + '<span ng-show="regionserverunhealtynum">{{regionserverunhealtynum}}</span><span ng-show="!regionserverunhealtynum">0</span> Unhealthy)' + + '</a>' + + '</div>' + + '</div>' + + '<div class="icon">' + + '<i class="fa fa-taxi"></i>' + + '</div>' + + '</div>', + replace: true + }; + }); + + function withType(serviceType) { + /** + * Customize the widget content. Return false will prevent auto compile. + * @param {{}} $element + * @param {function} $element.append + */ + return function registerWidget($element) { + $element.append( + $("<div hadoop-metric-widget data-type='" + serviceType + "'>") + ); + }; + } + hadoopMetricApp.widget("availabilityHBaseChart", withType('HBase'), true); + }); +})(); http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hbase-web/src/main/webapp/package.json ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hbase-web/src/main/webapp/package.json b/eagle-metric/eagle-hbase-web/src/main/webapp/package.json new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hbase-web/src/test/org/apache/eagle/metric/HBaseMetricWebApplicationProviderTest.java ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hbase-web/src/test/org/apache/eagle/metric/HBaseMetricWebApplicationProviderTest.java b/eagle-metric/eagle-hbase-web/src/test/org/apache/eagle/metric/HBaseMetricWebApplicationProviderTest.java new file mode 100644 index 0000000..eae05e5 --- /dev/null +++ b/eagle-metric/eagle-hbase-web/src/test/org/apache/eagle/metric/HBaseMetricWebApplicationProviderTest.java @@ -0,0 +1,100 @@ +package org.apache.eagle.metric;/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import com.google.inject.Inject; +import org.apache.eagle.app.resource.ApplicationResource; +import org.apache.eagle.app.service.ApplicationOperations; +import org.apache.eagle.app.test.ApplicationTestBase; +import org.apache.eagle.metadata.model.ApplicationEntity; +import org.apache.eagle.metadata.model.SiteEntity; +import org.apache.eagle.metadata.resource.SiteResource; +import org.apache.eagle.metadata.service.ApplicationStatusUpdateService; +import org.junit.Assert; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +/** + * @Since 2/20/17. + */ +public class HBaseMetricWebApplicationProviderTest extends ApplicationTestBase { + @Inject + private SiteResource siteResource; + + @Inject + private ApplicationResource applicationResource; + + @Inject + private ApplicationStatusUpdateService statusUpdateService; + + private void installDependencies(){ + ApplicationOperations.InstallOperation installDependency1 = new ApplicationOperations.InstallOperation("test_site", "TOPOLOGY_HEALTH_CHECK_APP", ApplicationEntity.Mode.LOCAL); + applicationResource.installApplication(installDependency1); + + ApplicationOperations.InstallOperation installDependency2 = new ApplicationOperations.InstallOperation("test_site", "HADOOP_METRIC_MONITOR", ApplicationEntity.Mode.LOCAL); + applicationResource.installApplication(installDependency2); + } + + /** + * register site + * install app + * start app + * stop app + * uninstall app + * + * @throws InterruptedException + */ + @Test + public void testApplicationLifecycle() throws InterruptedException { + // Create local site + SiteEntity siteEntity = new SiteEntity(); + siteEntity.setSiteId("test_site"); + siteEntity.setSiteName("Test Site"); + siteEntity.setDescription("Test Site for HBASE_METRIC_WEB_APP"); + siteResource.createSite(siteEntity); + Assert.assertNotNull(siteEntity.getUuid()); + + + + ApplicationOperations.InstallOperation installOperation = new ApplicationOperations.InstallOperation("test_site", "HBASE_METRIC_WEB_APP", ApplicationEntity.Mode.LOCAL); + installOperation.setConfiguration(getConf()); + installDependencies(); + // Install application + ApplicationEntity applicationEntity = applicationResource.installApplication(installOperation).getData(); + //Todo: comment these for now, because they haven't been implemented + // Start application +// applicationResource.startApplication(new ApplicationOperations.StartOperation(applicationEntity.getUuid())); +// // Stop application +// applicationResource.stopApplication(new ApplicationOperations.StopOperation(applicationEntity.getUuid())); + //Uninstall application + awaitApplicationStop(applicationEntity); + applicationResource.uninstallApplication(new ApplicationOperations.UninstallOperation(applicationEntity.getUuid())); + try { + applicationResource.getApplicationEntityByUUID(applicationEntity.getUuid()); + Assert.fail("Application instance (UUID: " + applicationEntity.getUuid() + ") should have been uninstalled"); + } catch (Exception ex) { + // Expected exception + } + } + + private Map<String, Object> getConf() { + Map<String, Object> conf = new HashMap<>(); + conf.put("service.host", "localhost"); + conf.put("service.port", "9090"); + return conf; + } +} http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hdfs-web/pom.xml ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hdfs-web/pom.xml b/eagle-metric/eagle-hdfs-web/pom.xml new file mode 100644 index 0000000..dd38416 --- /dev/null +++ b/eagle-metric/eagle-hdfs-web/pom.xml @@ -0,0 +1,57 @@ +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>eagle-metric-parent</artifactId> + <groupId>org.apache.eagle</groupId> + <version>0.5.0-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + <artifactId>eagle-hdfs-web</artifactId> + <name>Eagle::App::HadoopMetric::Hdfs::WebUI</name> + <dependencies> + <dependency> + <groupId>org.apache.eagle</groupId> + <artifactId>eagle-app-base</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>org.apache.eagle</groupId> + <artifactId>eagle-hadoop-metric</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.apache.eagle</groupId> + <artifactId>eagle-topology-app</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + </dependencies> + <build> + <resources> + <resource> + <directory>src/main/webapp/app</directory> + <targetPath>assets/</targetPath> + </resource> + <resource> + <directory>src/main/resources</directory> + </resource> + </resources> + </build> +</project> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hdfs-web/src/main/java/org/apache/eagle/metric/HdfsMetricWebApplicationProvider.java ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hdfs-web/src/main/java/org/apache/eagle/metric/HdfsMetricWebApplicationProvider.java b/eagle-metric/eagle-hdfs-web/src/main/java/org/apache/eagle/metric/HdfsMetricWebApplicationProvider.java new file mode 100644 index 0000000..434e1f4 --- /dev/null +++ b/eagle-metric/eagle-hdfs-web/src/main/java/org/apache/eagle/metric/HdfsMetricWebApplicationProvider.java @@ -0,0 +1,23 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.eagle.metric; + +import org.apache.eagle.app.StaticApplicationProvider; + +public class HdfsMetricWebApplicationProvider extends StaticApplicationProvider { + // HdfsWebApplicationProvider SPI Interface +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hdfs-web/src/main/resources/META-INF/providers/org.apache.eagle.metric.HdfsMetricWebApplicationProvider.xml ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hdfs-web/src/main/resources/META-INF/providers/org.apache.eagle.metric.HdfsMetricWebApplicationProvider.xml b/eagle-metric/eagle-hdfs-web/src/main/resources/META-INF/providers/org.apache.eagle.metric.HdfsMetricWebApplicationProvider.xml new file mode 100644 index 0000000..b6f70d1 --- /dev/null +++ b/eagle-metric/eagle-hdfs-web/src/main/resources/META-INF/providers/org.apache.eagle.metric.HdfsMetricWebApplicationProvider.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<application> + <type>HDFS_METRIC_WEB_APP</type> + <name>Hdfs Metric Monitoring Web </name> + <viewPath>/apps/hdfs</viewPath> + <description>Hdfs Metric Monitoring Web</description> + <dependencies> + <dependency> + <type>HADOOP_METRIC_MONITOR</type> + <required>true</required> + </dependency> + <dependency> + <type>TOPOLOGY_HEALTH_CHECK_APP</type> + <required>true</required> + </dependency> + </dependencies> + <configuration> + <property> + <name>service.host</name> + <displayName>Eagle Service Host</displayName> + <description>Set additional eagle service host, default: using current host</description> + </property> + <property> + <name>service.port</name> + <displayName>Eagle Service Port</displayName> + <description>Set additional eagle service port, default: using current port</description> + </property> + </configuration> +</application> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hdfs-web/src/main/resources/META-INF/services/org.apache.eagle.app.spi.ApplicationProvider ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hdfs-web/src/main/resources/META-INF/services/org.apache.eagle.app.spi.ApplicationProvider b/eagle-metric/eagle-hdfs-web/src/main/resources/META-INF/services/org.apache.eagle.app.spi.ApplicationProvider new file mode 100644 index 0000000..3dec9d0 --- /dev/null +++ b/eagle-metric/eagle-hdfs-web/src/main/resources/META-INF/services/org.apache.eagle.app.spi.ApplicationProvider @@ -0,0 +1,16 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +org.apache.eagle.metric.HdfsMetricWebApplicationProvider \ No newline at end of file http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/ctrl/overview.js ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/ctrl/overview.js b/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/ctrl/overview.js new file mode 100644 index 0000000..b8d57a7 --- /dev/null +++ b/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/ctrl/overview.js @@ -0,0 +1,29 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function () { + /** + * `register` without params will load the module which using require + */ + register(function (hdfsMetricApp) { + hdfsMetricApp.controller("overviewCtrl", function (PageConfig) { + PageConfig.title = 'Hdfs'; + + }); + }); +})(); http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/index.html ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/index.html b/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/index.html new file mode 100644 index 0000000..799ad15 --- /dev/null +++ b/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/index.html @@ -0,0 +1,6 @@ +<htm> + <body> + <h1>HDFS Metric Monitor Application!</h1> + <i><b>url</b>: /apps/hdfs</i> + </body> +</htm> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/index.js ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/index.js b/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/index.js new file mode 100644 index 0000000..48b3feb --- /dev/null +++ b/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/index.js @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function () { + /** + * `register` is global function that for application to set up 'controller', 'service', 'directive', 'route' in Eagle + */ + var hdfsMetricApp = register(['ngRoute', 'ngAnimate', 'ui.router', 'eagle.service']); + + hdfsMetricApp.route("HdfsMetric", { + url: "/hadoopService/hdfs", + site: true, + templateUrl: "partials/overview.html", + controller: "overviewCtrl", + resolve: {time: true} + }); + + hdfsMetricApp.portal({ + name: "Services", icon: "heartbeat", list: [ + {name: "HDFS", path: "hadoopService/hdfs"} + ] + }, true); + + hdfsMetricApp.requireCSS("style/index.css"); + hdfsMetricApp.require("widget/availabilityChart.js"); + hdfsMetricApp.require("ctrl/overview.js"); +})(); http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/partials/overview.html ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/partials/overview.html b/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/partials/overview.html new file mode 100644 index 0000000..678b221 --- /dev/null +++ b/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/partials/overview.html @@ -0,0 +1,17 @@ +<!-- + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + --> + +HDFS Page http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/style/index.css ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/style/index.css b/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/style/index.css new file mode 100644 index 0000000..aa215ab --- /dev/null +++ b/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/style/index.css @@ -0,0 +1,88 @@ +@CHARSET "UTF-8"; +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.hadoopMetric-chart { + position: relative; + margin-bottom: 15px; +} + +.hadoopMetric-chart h3 { + font-size: 20px; + margin: 10px 0 0 0; +} + +.hadoopMetric-chart .hadoopMetric-chart-container { + height: 300px; + position: relative; +} + +.hadoopMetric-chart .hadoopMetric-no-chart-data { + position:absolute; + left: 38%; + top: 40%; + font-size: 20px; + color: #999; +} + +.with-border .hadoopMetric-chart { + padding-bottom: 15px; + margin-bottom: 15px; + border-bottom: 1px solid #f4f4f4; +} + +.with-border .hadoopMetric-chart:last-child { + padding-bottom: 0; + margin-bottom: 0; + border-bottom: 0; +} + +.hadoopMetric-widget { + width: 100%; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1); + border-radius: 2px; + padding: 10px; +} + +.hadoopMetric-widget h3 { + margin: 0; + padding: 0; +} + +.hadoopMetric-widget .hadoopMetric-chart-container { + height: 100px; +} + +.hadoopMetric-summary-a { + color: #fff; +} + +.small-box.hadoopMetric-widget { + margin: 0; + height: 100%; + min-height: 110px; +} + +.hadoopMetric-widget-detail { + margin-left: 12px; + margin-top: 10px; +} + +.hadoopMetric-table { + text-align: right; +} http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/widget/availabilityChart.js ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/widget/availabilityChart.js b/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/widget/availabilityChart.js new file mode 100644 index 0000000..fbfc73d --- /dev/null +++ b/eagle-metric/eagle-hdfs-web/src/main/webapp/app/apps/hdfs/widget/availabilityChart.js @@ -0,0 +1,105 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +(function () { + /** + * `register` without params will load the module which using require + */ + register(function (hdfsMetricApp) { + var COLOR_MAPPING = { + HDFS: 'orange', + HBase: 'yellow', + Yarn: 'green', + }; + + var widgetChartOption = { + color: ['#FFFFFF'], + grid: { + top: 0, + right: 0, + bottom: 0, + left: 0, + containLabel: false, + }, + xAxis: { + axisLine: {show: false}, + axisLabel: {show: false}, + }, + yAxis: [{ + axisLine: {show: false}, + axisLabel: {show: false}, + axisTick: {show: false}, + splitLine: {show: false}, + }], + }; + + hdfsMetricApp.directive("hdfsMetricWidget", function () { + return { + restrict: 'AE', + controller: function($scope, $attrs) { + // Get site + var site = $scope.site; + + // Get type + $scope.type = $attrs.type; + + // Customize chart color + $scope.bgColor = COLOR_MAPPING[$scope.type]; + + $scope.chartOption = widgetChartOption; + + // Mock fetch data + var now = +new Date(); + var data = []; + for(var j = 0 ; j < 30 ; j += 1) { + data.push({x: now + j * 1000 * 60, y: Math.random() * 100}); + } + $scope.series = [{ + name: '', + type: 'line', + data: data, + showSymbol: false, + }]; + + // Ref: jpm widget if need keep refresh the widget + }, + template: + '<div class="hadoopMetric-widget bg-{{bgColor}}">' + + '<h3>{{type}}</h3>' + + '<div chart class="hadoopMetric-chart-container" series="series" option="chartOption"></div>' + + '</div>', + replace: true + }; + }); + + function withType(serviceType) { + /** + * Customize the widget content. Return false will prevent auto compile. + * @param {{}} $element + * @param {function} $element.append + */ + return function registerWidget($element) { + $element.append( + $("<div hdfs-metric-widget data-type='" + serviceType + "'>") + ); + } + } + + hdfsMetricApp.widget("availabilityHdfsChart", withType('HDFS'), true); + }); +})(); http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hdfs-web/src/main/webapp/package.json ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hdfs-web/src/main/webapp/package.json b/eagle-metric/eagle-hdfs-web/src/main/webapp/package.json new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/eagle/blob/c32b7152/eagle-metric/eagle-hdfs-web/src/test/org/apache/eagle/metric/HdfsMetricWebApplicationProviderTest.java ---------------------------------------------------------------------- diff --git a/eagle-metric/eagle-hdfs-web/src/test/org/apache/eagle/metric/HdfsMetricWebApplicationProviderTest.java b/eagle-metric/eagle-hdfs-web/src/test/org/apache/eagle/metric/HdfsMetricWebApplicationProviderTest.java new file mode 100644 index 0000000..8e61af4 --- /dev/null +++ b/eagle-metric/eagle-hdfs-web/src/test/org/apache/eagle/metric/HdfsMetricWebApplicationProviderTest.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * <p/> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p/> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.eagle.metric; +import com.google.inject.Inject; +import org.apache.eagle.app.resource.ApplicationResource; +import org.apache.eagle.app.service.ApplicationOperations; +import org.apache.eagle.app.test.ApplicationTestBase; +import org.apache.eagle.metadata.model.ApplicationEntity; +import org.apache.eagle.metadata.model.SiteEntity; +import org.apache.eagle.metadata.resource.SiteResource; +import org.apache.eagle.metadata.service.ApplicationStatusUpdateService; +import org.junit.Assert; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +/** + * @Since 2/20/17. + */ +public class HdfsMetricWebApplicationProviderTest extends ApplicationTestBase { + @Inject + private SiteResource siteResource; + + @Inject + private ApplicationResource applicationResource; + + @Inject + private ApplicationStatusUpdateService statusUpdateService; + + private void installDependencies(){ + ApplicationOperations.InstallOperation installDependency1 = new ApplicationOperations.InstallOperation("test_site", "TOPOLOGY_HEALTH_CHECK_APP", ApplicationEntity.Mode.LOCAL); + applicationResource.installApplication(installDependency1); + + ApplicationOperations.InstallOperation installDependency2 = new ApplicationOperations.InstallOperation("test_site", "HADOOP_METRIC_MONITOR", ApplicationEntity.Mode.LOCAL); + applicationResource.installApplication(installDependency2); + } + + /** + * register site + * install app + * start app + * stop app + * uninstall app + * + * @throws InterruptedException + */ + @Test + public void testApplicationLifecycle() throws InterruptedException { + // Create local site + SiteEntity siteEntity = new SiteEntity(); + siteEntity.setSiteId("test_site"); + siteEntity.setSiteName("Test Site"); + siteEntity.setDescription("Test Site for HDFS_METRIC_WEB_APP"); + siteResource.createSite(siteEntity); + Assert.assertNotNull(siteEntity.getUuid()); + + + + ApplicationOperations.InstallOperation installOperation = new ApplicationOperations.InstallOperation("test_site", "HDFS_METRIC_WEB_APP", ApplicationEntity.Mode.LOCAL); + installOperation.setConfiguration(getConf()); + installDependencies(); + // Install application + ApplicationEntity applicationEntity = applicationResource.installApplication(installOperation).getData(); + //Todo: comment these for now, because they haven't been implemented + // Start application +// applicationResource.startApplication(new ApplicationOperations.StartOperation(applicationEntity.getUuid())); +// // Stop application +// applicationResource.stopApplication(new ApplicationOperations.StopOperation(applicationEntity.getUuid())); + //Uninstall application + awaitApplicationStop(applicationEntity); + applicationResource.uninstallApplication(new ApplicationOperations.UninstallOperation(applicationEntity.getUuid())); + try { + applicationResource.getApplicationEntityByUUID(applicationEntity.getUuid()); + Assert.fail("Application instance (UUID: " + applicationEntity.getUuid() + ") should have been uninstalled"); + } catch (Exception ex) { + // Expected exception + } + } + + private Map<String, Object> getConf() { + Map<String, Object> conf = new HashMap<>(); + conf.put("service.host", "localhost"); + conf.put("service.port", "9090"); + return conf; + } +}
