浏览代码

HDFS-13197. Ozone: Fix ConfServlet#getOzoneTags cmd. Contributed by Ajay Kumar.

Xiaoyu Yao 7 年之前
父节点
当前提交
908ddab55b

+ 181 - 0
hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/conf/HddsConfServlet.java

@@ -0,0 +1,181 @@
+/**
+ * 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.
+ */
+package org.apache.hadoop.hdds.conf;
+
+import com.google.gson.Gson;
+import java.io.IOException;
+import java.io.Writer;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.HttpHeaders;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.http.HttpServer2;
+
+import com.google.common.annotations.VisibleForTesting;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A servlet to print out the running configuration data.
+ */
+@InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"})
+@InterfaceStability.Unstable
+public class HddsConfServlet extends HttpServlet {
+
+  private static final long serialVersionUID = 1L;
+
+  protected static final String FORMAT_JSON = "json";
+  protected static final String FORMAT_XML = "xml";
+  private static final String COMMAND = "cmd";
+  private static final OzoneConfiguration OZONE_CONFIG =
+      new OzoneConfiguration();
+  transient Logger LOG = LoggerFactory.getLogger(HddsConfServlet.class);
+
+
+  /**
+   * Return the Configuration of the daemon hosting this servlet.
+   * This is populated when the HttpServer starts.
+   */
+  private Configuration getConfFromContext() {
+    Configuration conf = (Configuration) getServletContext().getAttribute(
+        HttpServer2.CONF_CONTEXT_ATTRIBUTE);
+    assert conf != null;
+    return conf;
+  }
+
+  @Override
+  public void doGet(HttpServletRequest request, HttpServletResponse response)
+      throws ServletException, IOException {
+
+    if (!HttpServer2.isInstrumentationAccessAllowed(getServletContext(),
+        request, response)) {
+      return;
+    }
+
+    String format = parseAcceptHeader(request);
+    if (FORMAT_XML.equals(format)) {
+      response.setContentType("text/xml; charset=utf-8");
+    } else if (FORMAT_JSON.equals(format)) {
+      response.setContentType("application/json; charset=utf-8");
+    }
+
+    String name = request.getParameter("name");
+    Writer out = response.getWriter();
+    String cmd = request.getParameter(COMMAND);
+
+    processCommand(cmd, format, request, response, out, name);
+    out.close();
+  }
+
+  private void processCommand(String cmd, String format,
+      HttpServletRequest request, HttpServletResponse response, Writer out,
+      String name)
+      throws IOException {
+    try {
+      if (cmd == null) {
+        if (FORMAT_XML.equals(format)) {
+          response.setContentType("text/xml; charset=utf-8");
+        } else if (FORMAT_JSON.equals(format)) {
+          response.setContentType("application/json; charset=utf-8");
+        }
+
+        writeResponse(getConfFromContext(), out, format, name);
+      } else {
+        processConfigTagRequest(request, out);
+      }
+    } catch (BadFormatException bfe) {
+      response.sendError(HttpServletResponse.SC_BAD_REQUEST, bfe.getMessage());
+    } catch (IllegalArgumentException iae) {
+      response.sendError(HttpServletResponse.SC_NOT_FOUND, iae.getMessage());
+    }
+  }
+
+  @VisibleForTesting
+  static String parseAcceptHeader(HttpServletRequest request) {
+    String format = request.getHeader(HttpHeaders.ACCEPT);
+    return format != null && format.contains(FORMAT_JSON) ?
+        FORMAT_JSON : FORMAT_XML;
+  }
+
+  /**
+   * Guts of the servlet - extracted for easy testing.
+   */
+  static void writeResponse(Configuration conf,
+      Writer out, String format, String propertyName)
+      throws IOException, IllegalArgumentException, BadFormatException {
+    if (FORMAT_JSON.equals(format)) {
+      Configuration.dumpConfiguration(conf, propertyName, out);
+    } else if (FORMAT_XML.equals(format)) {
+      conf.writeXml(propertyName, out);
+    } else {
+      throw new BadFormatException("Bad format: " + format);
+    }
+  }
+
+  public static class BadFormatException extends Exception {
+
+    private static final long serialVersionUID = 1L;
+
+    public BadFormatException(String msg) {
+      super(msg);
+    }
+  }
+
+  private void processConfigTagRequest(HttpServletRequest request,
+      Writer out) throws IOException {
+    String cmd = request.getParameter(COMMAND);
+    Gson gson = new Gson();
+    Configuration config = getOzoneConfig();
+
+    switch (cmd) {
+      case "getOzoneTags":
+        out.write(gson.toJson(config.get("ozone.system.tags").split(",")));
+        break;
+      case "getPropertyByTag":
+        String tags = request.getParameter("tags");
+        Map<String, Properties> propMap = new HashMap<>();
+
+        for (String tag : tags.split(",")) {
+          if (config.isPropertyTag(tag)) {
+            Properties properties = config.getAllPropertiesByTag(tag);
+            propMap.put(tag, properties);
+          } else {
+            LOG.debug("Not a valid tag" + tag);
+          }
+        }
+        out.write(gson.toJsonTree(propMap).toString());
+        break;
+      default:
+        throw new IllegalArgumentException(cmd + " is not a valid command.");
+    }
+
+  }
+
+  private static Configuration getOzoneConfig() {
+    return OZONE_CONFIG;
+  }
+}

+ 10 - 0
hadoop-hdds/common/src/main/resources/ozone-default.xml

@@ -993,6 +993,16 @@
     </description>
     </description>
   </property>
   </property>
 
 
+  <property>
+    <name>hadoop.custom.tags</name>
+    <value>OZONE,MANAGEMENT,SECURITY,PERFORMANCE,DEBUG,CLIENT,SERVER,KSM,SCM,CRITICAL,RATIS,CONTAINER,REQUIRED,REST,STORAGE,PIPELINE,STANDALONE</value>
+  </property>
+
+  <property>
+    <name>ozone.system.tags</name>
+    <value>OZONE,MANAGEMENT,SECURITY,PERFORMANCE,DEBUG,CLIENT,SERVER,KSM,SCM,CRITICAL,RATIS,CONTAINER,REQUIRED,REST,STORAGE,PIPELINE,STANDALONE</value>
+  </property>
+
 
 
   <property>
   <property>
     <name>hdds.rest.rest-csrf.enabled</name>
     <name>hdds.rest.rest-csrf.enabled</name>

+ 7 - 3
hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/BaseHttpServer.java

@@ -21,6 +21,7 @@ import com.google.common.base.Optional;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hdfs.DFSConfigKeys;
 import org.apache.hadoop.hdfs.DFSConfigKeys;
 import org.apache.hadoop.hdfs.DFSUtil;
 import org.apache.hadoop.hdfs.DFSUtil;
+import org.apache.hadoop.hdds.conf.HddsConfServlet;
 import org.apache.hadoop.http.HttpConfig;
 import org.apache.hadoop.http.HttpConfig;
 import org.apache.hadoop.http.HttpServer2;
 import org.apache.hadoop.http.HttpServer2;
 import org.apache.hadoop.net.NetUtils;
 import org.apache.hadoop.net.NetUtils;
@@ -79,6 +80,7 @@ public abstract class BaseHttpServer {
       builder.configureXFrame(xFrameEnabled).setXFrameOption(xFrameOptionValue);
       builder.configureXFrame(xFrameEnabled).setXFrameOption(xFrameOptionValue);
 
 
       httpServer = builder.build();
       httpServer = builder.build();
+      httpServer.addServlet("conf", "/conf", HddsConfServlet.class);
 
 
     }
     }
 
 
@@ -86,17 +88,19 @@ public abstract class BaseHttpServer {
 
 
   /**
   /**
    * Add a servlet to BaseHttpServer.
    * Add a servlet to BaseHttpServer.
+   *
    * @param servletName The name of the servlet
    * @param servletName The name of the servlet
-   * @param pathSpec The path spec for the servlet
-   * @param clazz The servlet class
+   * @param pathSpec    The path spec for the servlet
+   * @param clazz       The servlet class
    */
    */
   protected void addServlet(String servletName, String pathSpec,
   protected void addServlet(String servletName, String pathSpec,
-                            Class<? extends HttpServlet> clazz) {
+      Class<? extends HttpServlet> clazz) {
     httpServer.addServlet(servletName, pathSpec, clazz);
     httpServer.addServlet(servletName, pathSpec, clazz);
   }
   }
 
 
   /**
   /**
    * Returns the WebAppContext associated with this HttpServer.
    * Returns the WebAppContext associated with this HttpServer.
+   *
    * @return WebAppContext
    * @return WebAppContext
    */
    */
   protected WebAppContext getWebAppContext() {
   protected WebAppContext getWebAppContext() {

+ 350 - 318
hadoop-hdds/framework/src/main/resources/webapps/static/ozone.js

@@ -15,341 +15,373 @@
  * See the License for the specific language governing permissions and
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * limitations under the License.
  */
  */
-(function () {
-    "use strict";
-
-    var isIgnoredJmxKeys = function (key) {
-        return key == 'name' || key == 'modelerType' || key == "$$hashKey" ||
-            key.match(/tag.*/);
-    };
-    angular.module('ozone', ['nvd3', 'ngRoute']);
-    angular.module('ozone').config(function ($routeProvider) {
-        $routeProvider
-            .when("/", {
-                templateUrl: "main.html"
-            })
-            .when("/metrics/rpc", {
-                template: "<rpc-metrics></rpc-metrics>"
-            })
-            .when("/config", {
-                template: "<config></config>"
-            })
-    });
-    angular.module('ozone').component('overview', {
-        templateUrl: 'static/templates/overview.html',
-        transclude: true,
-        controller: function ($http) {
-            var ctrl = this;
-            $http.get("jmx?qry=Hadoop:service=*,name=*,component=ServerRuntime")
-                .then(function (result) {
-                    ctrl.jmx = result.data.beans[0]
-                })
-        }
-    });
-    angular.module('ozone').component('jvmParameters', {
-        templateUrl: 'static/templates/jvm.html',
-        controller: function ($http) {
-            var ctrl = this;
-            $http.get("jmx?qry=java.lang:type=Runtime")
-                .then(function (result) {
-                    ctrl.jmx = result.data.beans[0];
-
-                    //convert array to a map
-                    var systemProperties = {};
-                    for (var idx in ctrl.jmx.SystemProperties) {
-                        var item = ctrl.jmx.SystemProperties[idx];
-                        systemProperties[item.key.replace(/\./g, "_")] = item.value;
-                    }
-                    ctrl.jmx.SystemProperties = systemProperties;
-                })
-        }
-    });
+(function() {
+  "use strict";
+
+  var isIgnoredJmxKeys = function(key) {
+    return key == 'name' || key == 'modelerType' || key == "$$hashKey" ||
+      key.match(/tag.*/);
+  };
+  angular.module('ozone', ['nvd3', 'ngRoute']);
+  angular.module('ozone').config(function($routeProvider) {
+    $routeProvider
+      .when("/", {
+        templateUrl: "main.html"
+      })
+      .when("/metrics/rpc", {
+        template: "<rpc-metrics></rpc-metrics>"
+      })
+      .when("/config", {
+        template: "<config></config>"
+      })
+  });
+  angular.module('ozone').component('overview', {
+    templateUrl: 'static/templates/overview.html',
+    transclude: true,
+    controller: function($http) {
+      var ctrl = this;
+      $http.get("jmx?qry=Hadoop:service=*,name=*,component=ServerRuntime")
+        .then(function(result) {
+          ctrl.jmx = result.data.beans[0]
+        })
+    }
+  });
+  angular.module('ozone').component('jvmParameters', {
+    templateUrl: 'static/templates/jvm.html',
+    controller: function($http) {
+      var ctrl = this;
+      $http.get("jmx?qry=java.lang:type=Runtime")
+        .then(function(result) {
+          ctrl.jmx = result.data.beans[0];
+
+          //convert array to a map
+          var systemProperties = {};
+          for (var idx in ctrl.jmx.SystemProperties) {
+            var item = ctrl.jmx.SystemProperties[idx];
+            systemProperties[item.key.replace(/\./g, "_")] = item.value;
+          }
+          ctrl.jmx.SystemProperties = systemProperties;
+        })
+    }
+  });
+
+  angular.module('ozone').component('rpcMetrics', {
+    template: '<h1>Rpc metrics</h1><tabs>' +
+      '<pane ng-repeat="metric in $ctrl.metrics" ' +
+      'title="{{metric[\'tag.serverName\']}} ({{metric[\'tag.port\']}})">' +
+      '<rpc-metric jmxdata="metric"></rpc-metric></pane>' +
+      '</tabs>',
+    controller: function($http) {
+      var ctrl = this;
+      $http.get("jmx?qry=Hadoop:service=*,name=RpcActivityForPort*")
+        .then(function(result) {
+          ctrl.metrics = result.data.beans;
+        })
+    }
+  });
+  angular.module('ozone').component('rpcMetric', {
+    bindings: {
+      jmxdata: '<'
+    },
+    templateUrl: 'static/templates/rpc-metrics.html',
+    controller: function() {
+      var ctrl = this;
+
 
 
-    angular.module('ozone').component('rpcMetrics', {
-        template: '<h1>Rpc metrics</h1><tabs>' +
-        '<pane ng-repeat="metric in $ctrl.metrics" ' +
-        'title="{{metric[\'tag.serverName\']}} ({{metric[\'tag.port\']}})">' +
-        '<rpc-metric jmxdata="metric"></rpc-metric></pane>' +
-        '</tabs>',
-        controller: function ($http) {
-            var ctrl = this;
-            $http.get("jmx?qry=Hadoop:service=*,name=RpcActivityForPort*")
-                .then(function (result) {
-                    ctrl.metrics = result.data.beans;
-                })
+      ctrl.percentileGraphOptions = {
+        chart: {
+          type: 'discreteBarChart',
+          height: 450,
+          margin: {
+            top: 20,
+            right: 20,
+            bottom: 50,
+            left: 55
+          },
+          x: function(d) {
+            return d.label;
+          },
+          y: function(d) {
+            return d.value;
+          },
+          showValues: true,
+          valueFormat: function(d) {
+            return d3.format(',.1f')(d);
+          },
+          duration: 500,
+          xAxis: {
+            axisLabel: 'Percentage'
+          },
+          yAxis: {
+            axisLabel: 'Latency (ms)',
+            axisLabelDistance: -10
+          }
         }
         }
-    });
-    angular.module('ozone').component('rpcMetric', {
-        bindings: {
-            jmxdata: '<'
-        },
-        templateUrl: 'static/templates/rpc-metrics.html',
-        controller: function () {
-            var ctrl = this;
-
-
-            ctrl.percentileGraphOptions = {
-                chart: {
-                    type: 'discreteBarChart',
-                    height: 450,
-                    margin: {
-                        top: 20,
-                        right: 20,
-                        bottom: 50,
-                        left: 55
-                    },
-                    x: function (d) {
-                        return d.label;
-                    },
-                    y: function (d) {
-                        return d.value;
-                    },
-                    showValues: true,
-                    valueFormat: function (d) {
-                        return d3.format(',.1f')(d);
-                    },
-                    duration: 500,
-                    xAxis: {
-                        axisLabel: 'Percentage'
-                    },
-                    yAxis: {
-                        axisLabel: 'Latency (ms)',
-                        axisLabelDistance: -10
-                    }
-                }
+      };
+
+      ctrl.$onChanges = function(data) {
+        var groupedMetrics = {}
+
+        var createPercentageMetrics = function(metricName, window) {
+          groupedMetrics.percentiles = groupedMetrics['percentiles'] || {}
+          groupedMetrics.percentiles[window] = groupedMetrics.percentiles[window] || {};
+          groupedMetrics.percentiles[window][metricName] = groupedMetrics.percentiles[window][metricName] || {
+            graphdata: [{
+              key: window,
+              values: []
+            }],
+            numOps: 0
+          };
+
+        };
+        var metrics = ctrl.jmxdata;
+        for (var key in metrics) {
+          var percentile = key.match(/(.*Time)(\d+s)(\d+th)PercentileLatency/);
+          var percentileNumOps = key.match(/(.*Time)(\d+s)NumOps/);
+          var successFailures = key.match(/(.*)(Success|Failures)/);
+          var numAverages = key.match(/(.*Time)(NumOps|AvgTime)/);
+          if (percentile) {
+            var metricName = percentile[1];
+            var window = percentile[2];
+            var percentage = percentile[3]
+            createPercentageMetrics(metricName, window);
+
+
+            groupedMetrics.percentiles[window][metricName].graphdata[0]
+              .values.push({
+                label: percentage,
+                value: metrics[key]
+              })
+          } else if (successFailures) {
+            var metricName = successFailures[1];
+            groupedMetrics.successfailures = groupedMetrics['successfailures'] || {}
+            groupedMetrics.successfailures[metricName] = groupedMetrics.successfailures[metricName] || {
+              success: 0,
+              failures: 0
             };
             };
+            if (successFailures[2] == 'Success') {
+              groupedMetrics.successfailures[metricName].success = metrics[key];
+            } else {
+              groupedMetrics.successfailures[metricName].failures = metrics[key];
+            }
 
 
-            ctrl.$onChanges = function (data) {
-                var groupedMetrics = {}
-
-                var createPercentageMetrics = function (metricName, window) {
-                    groupedMetrics.percentiles = groupedMetrics['percentiles'] || {}
-                    groupedMetrics.percentiles[window] = groupedMetrics.percentiles[window] || {};
-                    groupedMetrics.percentiles[window][metricName] = groupedMetrics.percentiles[window][metricName] || {
-                            graphdata: [{
-                                key: window,
-                                values: []
-                            }], numOps: 0
-                        };
-
-                };
-                var metrics = ctrl.jmxdata;
-                for (var key in metrics) {
-                    var percentile = key.match(/(.*Time)(\d+s)(\d+th)PercentileLatency/);
-                    var percentileNumOps = key.match(/(.*Time)(\d+s)NumOps/);
-                    var successFailures = key.match(/(.*)(Success|Failures)/);
-                    var numAverages = key.match(/(.*Time)(NumOps|AvgTime)/);
-                    if (percentile) {
-                        var metricName = percentile[1];
-                        var window = percentile[2];
-                        var percentage = percentile[3]
-                        createPercentageMetrics(metricName, window);
-
-
-                        groupedMetrics.percentiles[window][metricName].graphdata[0]
-                            .values.push({
-                            label: percentage,
-                            value: metrics[key]
-                        })
-                    } else if (successFailures) {
-                        var metricName = successFailures[1];
-                        groupedMetrics.successfailures = groupedMetrics['successfailures'] || {}
-                        groupedMetrics.successfailures[metricName] = groupedMetrics.successfailures[metricName] || {
-                                success: 0,
-                                failures: 0
-                            };
-                        if (successFailures[2] == 'Success') {
-                            groupedMetrics.successfailures[metricName].success = metrics[key];
-                        } else {
-                            groupedMetrics.successfailures[metricName].failures = metrics[key];
-                        }
-
-                    } else if (numAverages) {
-                        var metricName = numAverages[1];
-                        groupedMetrics.numavgs = groupedMetrics['numavgs'] || {}
-                        groupedMetrics.numavgs[metricName] = groupedMetrics.numavgs[metricName] || {
-                                numOps: 0,
-                                avgTime: 0
-                            };
-                        if (numAverages[2] == 'NumOps') {
-                            groupedMetrics.numavgs[metricName].numOps = metrics[key];
-                        } else {
-                            groupedMetrics.numavgs[metricName].avgTime = metrics[key];
-                        }
-
-                    } else if (percentileNumOps) {
-                        var metricName = percentileNumOps[1];
-                        var window = percentileNumOps[2];
-                        createPercentageMetrics(metricName, window);
-                        groupedMetrics.percentiles[window][metricName].numOps = metrics[key];
-                    } else if (isIgnoredJmxKeys(key)) {
-                        //ignore
-                    } else {
-                        groupedMetrics.others = groupedMetrics.others || [];
-                        groupedMetrics.others.push({
-                            'key': key,
-                            'value': metrics[key]
-                        });
-                    }
-
-                }
-                ctrl.metrics = groupedMetrics;
+          } else if (numAverages) {
+            var metricName = numAverages[1];
+            groupedMetrics.numavgs = groupedMetrics['numavgs'] || {}
+            groupedMetrics.numavgs[metricName] = groupedMetrics.numavgs[metricName] || {
+              numOps: 0,
+              avgTime: 0
             };
             };
+            if (numAverages[2] == 'NumOps') {
+              groupedMetrics.numavgs[metricName].numOps = metrics[key];
+            } else {
+              groupedMetrics.numavgs[metricName].avgTime = metrics[key];
+            }
 
 
+          } else if (percentileNumOps) {
+            var metricName = percentileNumOps[1];
+            var window = percentileNumOps[2];
+            createPercentageMetrics(metricName, window);
+            groupedMetrics.percentiles[window][metricName].numOps = metrics[key];
+          } else if (isIgnoredJmxKeys(key)) {
+            //ignore
+          } else {
+            groupedMetrics.others = groupedMetrics.others || [];
+            groupedMetrics.others.push({
+              'key': key,
+              'value': metrics[key]
+            });
+          }
+
+        }
+        ctrl.metrics = groupedMetrics;
+      };
+
+    }
+  });
+  angular.module('ozone')
+    .component('tabs', {
+      transclude: true,
+      controller: function($scope) {
+        var ctrl = this;
+        var panes = this.panes = [];
+        this.select = function(pane) {
+          angular.forEach(panes, function(pane) {
+            pane.selected = false;
+          });
+          pane.selected = true;
+        };
+        this.addPane = function(pane) {
+          if (panes.length === 0) {
+            this.select(pane);
+          }
+          panes.push(pane);
+        };
+        this.click = function(pane) {
+          ctrl.select(pane);
         }
         }
+      },
+      template: '<div class="nav navtabs"><div class="row"><ul' +
+        ' class="nav nav-pills">' +
+        '<li ng-repeat="pane in $ctrl.panes" ng-class="{active:pane.selected}">' +
+        '<a href="" ng-click="$ctrl.click(pane)">{{pane.title}}</a> ' +
+        '</li> </ul></div><br/><div class="tab-content" ng-transclude></div> </div>'
+    })
+    .component('pane', {
+      transclude: true,
+      require: {
+        tabsCtrl: '^tabs'
+      },
+      bindings: {
+        title: '@'
+      },
+      controller: function() {
+        this.$onInit = function() {
+          this.tabsCtrl.addPane(this);
+        };
+      },
+      template: '<div class="tab-pane" ng-if="$ctrl.selected" ng-transclude></div>'
     });
     });
-    angular.module('ozone')
-        .component('tabs', {
-            transclude: true,
-            controller: function ($scope) {
-                var ctrl = this;
-                var panes = this.panes = [];
-                this.select = function (pane) {
-                    angular.forEach(panes, function (pane) {
-                        pane.selected = false;
-                    });
-                    pane.selected = true;
-                };
-                this.addPane = function (pane) {
-                    if (panes.length === 0) {
-                        this.select(pane);
-                    }
-                    panes.push(pane);
-                };
-                this.click = function(pane) {
-                    ctrl.select(pane);
-                }
-            },
-            template: '<div class="nav navtabs"><div class="row"><ul' +
-            ' class="nav nav-pills">' +
-            '<li ng-repeat="pane in $ctrl.panes" ng-class="{active:pane.selected}">' +
-            '<a href="" ng-click="$ctrl.click(pane)">{{pane.title}}</a> ' +
-            '</li> </ul></div><br/><div class="tab-content" ng-transclude></div> </div>'
-        })
-        .component('pane', {
-            transclude: true,
-            require: {
-                tabsCtrl: '^tabs'
-            },
-            bindings: {
-                title: '@'
-            },
-            controller: function () {
-                this.$onInit = function () {
-                    this.tabsCtrl.addPane(this);
-                };
-            },
-            template: '<div class="tab-pane" ng-if="$ctrl.selected" ng-transclude></div>'
+
+  angular.module('ozone').component('navmenu', {
+    bindings: {
+      metrics: '<'
+    },
+    templateUrl: 'static/templates/menu.html',
+    controller: function($http) {
+      var ctrl = this;
+      ctrl.docs = false;
+      $http.head("docs/index.html")
+        .then(function(result) {
+          ctrl.docs = true;
+        }, function() {
+          ctrl.docs = false;
         });
         });
+    }
+  });
+
+  angular.module('ozone').component('config', {
+    templateUrl: 'static/templates/config.html',
+    controller: function($scope, $http) {
+      var ctrl = this;
+      ctrl.selectedTags = [];
+      ctrl.configArray = [];
 
 
-    angular.module('ozone').component('navmenu', {
-        bindings: {
-            metrics: '<'
-        },
-        templateUrl: 'static/templates/menu.html',
-        controller: function ($http) {
-            var ctrl = this;
-            ctrl.docs = false;
-            $http.head("docs/index.html")
-                .then(function (result) {
-                    ctrl.docs = true;
-                },function(){
-                    ctrl.docs = false;
-                });
+      $http.get("conf?cmd=getOzoneTags")
+        .then(function(response) {
+          ctrl.tags = response.data;
+          var excludedTags = ['CBLOCK', 'KSM', 'SCM'];
+          for (var i = 0; i < excludedTags.length; i++) {
+            var idx = ctrl.tags.indexOf(excludedTags[i]);
+            // Remove CBLOCK related properties
+            if (idx > -1) {
+              ctrl.tags.splice(idx, 1);
+            }
+          }
+          ctrl.loadAll();
+        });
+
+      ctrl.convertToArray = function(srcObj) {
+        ctrl.keyTagMap = {};
+        for (var idx in srcObj) {
+          //console.log("Adding keys for "+idx)
+          for (var key in srcObj[idx]) {
+
+            if (ctrl.keyTagMap.hasOwnProperty(key)) {
+              ctrl.keyTagMap[key]['tag'].push(idx);
+            } else {
+              var newProp = {};
+              newProp['name'] = key;
+              newProp['value'] = srcObj[idx][key];
+              newProp['tag'] = [];
+              newProp['tag'].push(idx);
+              ctrl.keyTagMap[key] = newProp;
+            }
+          }
         }
         }
-    });
+      }
 
 
-    angular.module('ozone').component('config', {
-        templateUrl: 'static/templates/config.html',
-        controller: function ($scope, $http) {
-            var ctrl = this;
-            ctrl.selectedTags = [];
-
-            $http.get("conf?cmd=getOzoneTags&group=ozone")
-                .then(function (response) {
-                    ctrl.tags = response.data;
-
-                    var excludedTags = ['CBLOCK', 'KSM', 'SCM'];
-                    for (var i = 0; i < excludedTags.length; i++) {
-                        var idx = ctrl.tags.indexOf(excludedTags[i]);
-                        // Remove CBLOCK related properties
-                        if (idx > -1) {
-                            ctrl.tags.splice(idx, 1);
-                        }
-                    }
-                    ctrl.loadAll();
-                });
-
-
-
-            ctrl.loadAll = function () {
-                console.log("Displaying all configs");
-                $http.get("conf?cmd=getPropertyByTag&tags=" + ctrl.tags + "&group=ozone").then(function (response) {
-                    ctrl.configs = response.data;
-                    console.log(ctrl.configs)
-                    for (var idx in ctrl.configs) {
-                        var tags = []
-                        var parsedTags = ctrl.configs[idx].tag.split(",");
-                        for (var t in parsedTags) {
-                            tags.push(parsedTags[t].trim())
-                        }
-                        ctrl.configs[idx].tag = tags;
-
-                    };
-                    ctrl.sortBy('name');
-                });
-            };
+      ctrl.loadAll = function() {
+        $http.get("conf?cmd=getPropertyByTag&tags=KSM,SCM," + ctrl.tags)
+          .then(function(response) {
 
 
-            ctrl.tagFilter = function (value, index, array) {
-                if (!ctrl.selectedTags) {
-                    return true;
-                }
-                var selected = true;
-                for (var idx in ctrl.selectedTags) {
-                    selected = selected && (value.tag.indexOf(ctrl.selectedTags[idx]) > -1);
-                }
-                return selected;
-            };
-            ctrl.configFilter = function (config) {
-                return false;
-            };
-            ctrl.selected = function (tag) {
-                return ctrl.selectedTags.includes(tag);
-            };
+            ctrl.convertToArray(response.data);
+            ctrl.configs = Object.values(ctrl.keyTagMap);
+            ctrl.component = 'All';
+            console.log("ajay -> " + JSON.stringify(ctrl.configs));
+            ctrl.sortBy('name');
+          });
+      };
 
 
-            ctrl.allSelected = function () {
-                return ctrl.selectedTags.indexOf('SCM') == -1
-                    && ctrl.selectedTags.indexOf('KSM') == -1
-            };
+      ctrl.filterTags = function() {
+        if (!ctrl.selectedTags) {
+          return true;
+        }
 
 
-            ctrl.switchto = function (tag) {
-                var tags = ctrl.selectedTags.filter(function (item) {
-                    return item != 'KSM' && item != 'SCM';
-                });
-                if (tag) {
-                    tags.push(tag);
-                }
-                ctrl.selectedTags = tags;
-            };
+        if (ctrl.selectedTags.length < 1 && ctrl.component == 'All') {
+          return true;
+        }
 
 
-            ctrl.select = function (tag) {
-                var tagIdx = ctrl.selectedTags.indexOf(tag);
-                if (tagIdx > -1) {
-                    ctrl.selectedTags = ctrl.selectedTags.filter(function (item) {
-                        return item != tag;
-                    });
-                } else {
-                    ctrl.selectedTags.push(tag);
-                }
-                console.log("Tags selected:" + ctrl.selectedTags);
-            };
+        ctrl.configs = ctrl.configs.filter(function(item) {
 
 
-            ctrl.sortBy = function (propertyName) {
-                ctrl.reverse = (ctrl.propertyName === propertyName) ? !ctrl.reverse : false;
-                ctrl.propertyName = propertyName;
-            };
+          if (ctrl.component != 'All' && (item['tag'].indexOf(ctrl
+              .component) < 0)) {
+            console.log(item['name'] + " false tag " + item['tag']);
+            return false;
+          }
+
+          if (ctrl.selectedTags.length < 1) {
+            return true;
+          }
+          for (var tag in item['tag']) {
+            tag = item['tag'][tag];
+            if (ctrl.selectedTags.indexOf(tag) > -1) {
+              return true;
+            }
+          }
+          return false;
+        });
+
+      };
+      ctrl.configFilter = function(config) {
+        return false;
+      };
+      ctrl.selected = function(tag) {
+        return ctrl.selectedTags.includes(tag);
+      };
+
+      ctrl.switchto = function(tag) {
+        ctrl.component = tag;
+        ctrl.reloadConfig();
+      };
 
 
+      ctrl.select = function(tag) {
+        var tagIdx = ctrl.selectedTags.indexOf(tag);
+        if (tagIdx > -1) {
+          ctrl.selectedTags.splice(tagIdx, 1);
+        } else {
+          ctrl.selectedTags.push(tag);
         }
         }
-    });
+        ctrl.reloadConfig();
+      };
+
+      ctrl.reloadConfig = function() {
+        ctrl.configs = [];
+        ctrl.configs = Object.values(ctrl.keyTagMap);
+        ctrl.filterTags();
+      };
+
+      ctrl.sortBy = function(field) {
+        ctrl.reverse = (ctrl.propertyName === field) ? !ctrl.reverse : false;
+        ctrl.propertyName = field;
+      };
+
+      ctrl.allSelected = function(comp) {
+        //console.log("Adding key for compo ->"+comp)
+        return ctrl.component == comp;
+      };
+
+    }
+  });
 
 
-})();
+})();

+ 14 - 14
hadoop-hdds/framework/src/main/resources/webapps/static/templates/config.html

@@ -23,14 +23,14 @@
   <div class="col-md-10">
   <div class="col-md-10">
     <div class="btn-group btn-group-justified">
     <div class="btn-group btn-group-justified">
       <a class="btn"
       <a class="btn"
-         ng-class="$ctrl.allSelected() ? 'btn-primary' :'btn-secondary'"
-         ng-click="$ctrl.switchto('')">All
+         ng-class="$ctrl.allSelected('All') ? 'btn-primary' :'btn-secondary'"
+         ng-click="$ctrl.switchto('All')">All
       </a>
       </a>
       <a class="btn"
       <a class="btn"
-         ng-class="$ctrl.selected('KSM') ? 'btn-primary' :'btn-secondary'"
+         ng-class="$ctrl.allSelected('KSM') ? 'btn-primary' :'btn-secondary'"
          ng-click="$ctrl.switchto('KSM')">KSM</a>
          ng-click="$ctrl.switchto('KSM')">KSM</a>
       <a class="btn"
       <a class="btn"
-         ng-class="$ctrl.selected('SCM') ? 'btn-primary' :'btn-secondary'"
+         ng-class="$ctrl.allSelected('SCM') ? 'btn-primary' :'btn-secondary'"
          ng-click="$ctrl.switchto('SCM')">SCM</a>
          ng-click="$ctrl.switchto('SCM')">SCM</a>
     </div>
     </div>
   </div>
   </div>
@@ -61,26 +61,26 @@
       <thead>
       <thead>
       <tr>
       <tr>
         <th class="col-md-3" >
         <th class="col-md-3" >
-          <a href="#" ng-click="$ctrl.sortBy('name')">Property</a>
-          <span class="sortorder" ng-show="propertyName === 'name'"
-                ng-class="{reverse: reverse}">
-
+          <a href="javascript:void(0)" ng-click="$ctrl.sortBy('name')">Property</a>
+          <span class="sortorder" ng-show="$ctrl.propertyName === 'name'"
+                ng-class="{reverse: $ctrl.reverse}">
               </span>
               </span>
         </th>
         </th>
         <th class="col-md-2" style="word-wrap: break-word;">
         <th class="col-md-2" style="word-wrap: break-word;">
-          <a ng-click="$ctrl.sortBy('value')">Value</a>
-          <span class="sortorder" ng-show="propertyName === 'value'"
-                ng-class="{reverse: reverse}"></span>
+          <a href="javascript:void(0)" ng-click="$ctrl.sortBy('value')">Value</a>
+          <span class="sortorder" ng-show="$ctrl.propertyName === 'value'"
+                ng-class="{reverse: $ctrl.reverse}"></span>
         </th>
         </th>
         <th class="col-md-7">
         <th class="col-md-7">
-          <a href="#" ng-click="$ctrl.sortBy('description')">Description</a>
-          <span class="sortorder" ng-show="propertyName === 'description'"
+          <a href="javascript:void(0)" ng-click="$ctrl.sortBy('description')">Description</a>
+          <span class="sortorder" ng-show="$ctrl.propertyName === 'description'"
                 ng-class="{reverse: reverse}"></span>
                 ng-class="{reverse: reverse}"></span>
         </th>
         </th>
       </tr>
       </tr>
       </thead>
       </thead>
       <tbody>
       <tbody>
-      <tr ng-repeat="config in $ctrl.configs | filter:$ctrl.tagFilter | filter:search | orderBy:propertyName:reverse">
+      <tr
+          ng-repeat="config in $ctrl.configs | filter:search | orderBy:$ctrl.propertyName:$ctrl.reverse">
         <td style="word-wrap: break-word;">{{config.name}}</td>
         <td style="word-wrap: break-word;">{{config.name}}</td>
         <td style="word-wrap: break-word;">{{config.value}}</td>
         <td style="word-wrap: break-word;">{{config.value}}</td>
         <td style="word-wrap: break-word;">{{config.description}}</td>
         <td style="word-wrap: break-word;">{{config.description}}</td>