AMBARI-20424. AMS should skip network stats from virtual network interfaces. 
(mpapirkovskyy)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/db3c09bb
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/db3c09bb
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/db3c09bb

Branch: refs/heads/branch-feature-AMBARI-12556
Commit: db3c09bb6f64c8ad46301b8828f62a130d56dd52
Parents: 1cffdcd
Author: Myroslav Papirkovskyi <mpapyrkovs...@hortonworks.com>
Authored: Mon Mar 13 18:38:49 2017 +0200
Committer: Myroslav Papirkovskyi <mpapyrkovs...@hortonworks.com>
Committed: Mon Mar 13 18:38:49 2017 +0200

----------------------------------------------------------------------
 .../conf/unix/metric_monitor.ini                |   2 +
 .../src/main/python/core/config_reader.py       |   7 +-
 .../src/main/python/core/host_info.py           |  41 ++++--
 .../src/test/python/core/TestHostInfo.py        | 147 ++++++++++++++++++-
 .../0.1.0/configuration/ams-env.xml             |  16 ++
 .../0.1.0/package/scripts/params.py             |  23 +--
 .../package/templates/metric_monitor.ini.j2     |   2 +
 7 files changed, 212 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/db3c09bb/ambari-metrics/ambari-metrics-host-monitoring/conf/unix/metric_monitor.ini
----------------------------------------------------------------------
diff --git 
a/ambari-metrics/ambari-metrics-host-monitoring/conf/unix/metric_monitor.ini 
b/ambari-metrics/ambari-metrics-host-monitoring/conf/unix/metric_monitor.ini
index e98c65c..7fe7397 100644
--- a/ambari-metrics/ambari-metrics-host-monitoring/conf/unix/metric_monitor.ini
+++ b/ambari-metrics/ambari-metrics-host-monitoring/conf/unix/metric_monitor.ini
@@ -22,6 +22,8 @@ metrics_servers = localhost
 enable_time_threshold = false
 enable_value_threshold = false
 skip_disk_patterns =
+skip_virtual_interfaces = false
+skip_network_interfaces_patterns =
 
 [emitter]
 send_interval = 60

http://git-wip-us.apache.org/repos/asf/ambari/blob/db3c09bb/ambari-metrics/ambari-metrics-host-monitoring/src/main/python/core/config_reader.py
----------------------------------------------------------------------
diff --git 
a/ambari-metrics/ambari-metrics-host-monitoring/src/main/python/core/config_reader.py
 
b/ambari-metrics/ambari-metrics-host-monitoring/src/main/python/core/config_reader.py
index 7010187..5686c50 100644
--- 
a/ambari-metrics/ambari-metrics-host-monitoring/src/main/python/core/config_reader.py
+++ 
b/ambari-metrics/ambari-metrics-host-monitoring/src/main/python/core/config_reader.py
@@ -22,7 +22,6 @@ import ConfigParser
 import StringIO
 import json
 import os
-import ast
 from ambari_commons import OSConst
 from ambari_commons.os_family_impl import OsFamilyImpl
 
@@ -254,3 +253,9 @@ class Configuration:
 
   def get_disk_metrics_skip_pattern(self):
     return self.get("default", "skip_disk_patterns")
+
+  def get_virtual_interfaces_skip(self):
+    return self.get("default", "skip_virtual_interfaces")
+
+  def get_network_interfaces_skip_pattern(self):
+    return self.get("default", "skip_network_interfaces_patterns")

http://git-wip-us.apache.org/repos/asf/ambari/blob/db3c09bb/ambari-metrics/ambari-metrics-host-monitoring/src/main/python/core/host_info.py
----------------------------------------------------------------------
diff --git 
a/ambari-metrics/ambari-metrics-host-monitoring/src/main/python/core/host_info.py
 
b/ambari-metrics/ambari-metrics-host-monitoring/src/main/python/core/host_info.py
index 90f73fa..035c833 100644
--- 
a/ambari-metrics/ambari-metrics-host-monitoring/src/main/python/core/host_info.py
+++ 
b/ambari-metrics/ambari-metrics-host-monitoring/src/main/python/core/host_info.py
@@ -19,14 +19,14 @@ limitations under the License.
 '''
 
 import logging
-import psutil
+import operator
 import os
 import platform
-import time
-import threading
-import socket
-import operator
+import psutil
 import re
+import socket
+import threading
+import time
 from collections import namedtuple
 
 logger = logging.getLogger()
@@ -153,13 +153,22 @@ class HostInfo():
 
     net_stats = psutil.net_io_counters(True)
     new_net_stats = {}
+
+    skip_virtual_interfaces = self.get_virtual_network_interfaces() if 
self.__config.get_virtual_interfaces_skip() == 'True' else []
+    skip_network_patterns = self.__config.get_network_interfaces_skip_pattern()
+    skip_network_patterns_list = skip_network_patterns.split(',') if 
skip_network_patterns and skip_network_patterns != 'None' else []
     for interface, values in net_stats.iteritems():
-      if interface != 'lo':
-        new_net_stats = {'bytes_out': new_net_stats.get('bytes_out', 0) + 
values.bytes_sent,
-                         'bytes_in': new_net_stats.get('bytes_in', 0) + 
values.bytes_recv,
-                         'pkts_out': new_net_stats.get('pkts_out', 0) + 
values.packets_sent,
-                         'pkts_in': new_net_stats.get('pkts_in', 0) + 
values.packets_recv
-        }
+      if interface != 'lo' and not interface in skip_virtual_interfaces:
+        ignore_network = False
+        for p in skip_network_patterns_list:
+          if re.match(p, interface):
+            ignore_network = True
+        if not ignore_network:
+          new_net_stats = {'bytes_out': new_net_stats.get('bytes_out', 0) + 
values.bytes_sent,
+                           'bytes_in': new_net_stats.get('bytes_in', 0) + 
values.bytes_recv,
+                           'pkts_out': new_net_stats.get('pkts_out', 0) + 
values.packets_sent,
+                           'pkts_in': new_net_stats.get('pkts_in', 0) + 
values.packets_recv
+          }
 
     with self.__last_network_lock:
       result = dict((k, (v - self.__last_network_data.get(k, 0)) / delta) for 
k, v in new_net_stats.iteritems())
@@ -354,3 +363,13 @@ class HostInfo():
 
   def get_ip_address(self):
     return socket.gethostbyname(socket.getfqdn())
+
+  def get_virtual_network_interfaces(self):
+    sys_net_path = "/sys/class/net"
+    net_devices = []
+    if os.path.isdir(sys_net_path):
+      links = [f for f in os.listdir(sys_net_path) if 
os.path.islink(os.path.join(sys_net_path, f))]
+      for link in links:
+        if "devices/virtual" in os.readlink(os.path.join(sys_net_path, link)):
+          net_devices.append(link)
+    return net_devices

http://git-wip-us.apache.org/repos/asf/ambari/blob/db3c09bb/ambari-metrics/ambari-metrics-host-monitoring/src/test/python/core/TestHostInfo.py
----------------------------------------------------------------------
diff --git 
a/ambari-metrics/ambari-metrics-host-monitoring/src/test/python/core/TestHostInfo.py
 
b/ambari-metrics/ambari-metrics-host-monitoring/src/test/python/core/TestHostInfo.py
index 63a1ae1..1b249c7 100644
--- 
a/ambari-metrics/ambari-metrics-host-monitoring/src/test/python/core/TestHostInfo.py
+++ 
b/ambari-metrics/ambari-metrics-host-monitoring/src/test/python/core/TestHostInfo.py
@@ -18,13 +18,12 @@ See the License for the specific language governing 
permissions and
 limitations under the License.
 '''
 
+import collections
 import logging
-from host_info import HostInfo
 import platform
-from unittest import TestCase
+from host_info import HostInfo
 from mock.mock import patch, MagicMock
-from core.config_reader import Configuration
-import collections
+from unittest import TestCase
 
 logger = logging.getLogger()
 
@@ -205,5 +204,145 @@ class TestHostInfo(TestCase):
     self.assertEqual(disk_counter_per_disk['sdisk_sdb1_read_merged_count'], 16)
     self.assertEqual(disk_counter_per_disk['sdisk_sdb1_write_merged_count'], 
17)
 
+  @patch.object(HostInfo, "get_virtual_network_interfaces", new = 
MagicMock(return_value = ['etc11', 'etc2']))
+  @patch("psutil.net_io_counters")
+  def test_get_network_info_virtual_devices(self, net_io_counters):
+    Stats = collections.namedtuple('interface', ['bytes_sent', 'bytes_recv',
+                                                  'packets_sent', 
'packets_recv'
+                                                  ])
+
+    net_stats = Stats(bytes_sent = 0, bytes_recv = 1,
+                          packets_sent = 2, packets_recv = 3
+    )
+
+    all_net_stats = { 'etc11' : net_stats, 'etc2' : net_stats }
+    net_io_counters.return_value = all_net_stats
+
+    c = MagicMock()
+
+    #skip virtual devices
+    c.get_virtual_interfaces_skip.return_value = 'True'
+    hostinfo = HostInfo(c)
+    network_info = hostinfo.get_network_info()
+
+    self.assertEqual(network_info, {})
+
+    #do not skip virtual devices
+    c.get_virtual_interfaces_skip.return_value = 'False'
+    hostinfo = HostInfo(c)
+    network_info = hostinfo.get_network_info()
+
+    #len({'bytes_in': ..., 'pkts_in': ..., 'pkts_out': ..., 'bytes_out': ...}) 
== 4
+    self.assertEqual(len(network_info), 4)
+
+  @patch("psutil.net_io_counters")
+  def test_get_network_info_skip_by_pattern(self, net_io_counters):
+    Stats = collections.namedtuple('interface', ['bytes_sent', 'bytes_recv',
+                                                  'packets_sent', 
'packets_recv'
+                                                  ])
+
+    net_stats = Stats(bytes_sent = 0, bytes_recv = 1,
+                          packets_sent = 2, packets_recv = 3
+    )
+
+    all_net_stats = { 'etc11' : net_stats, 'etc2' : net_stats }
+    net_io_counters.return_value = all_net_stats
+
+    c = MagicMock()
+
+    #skip all by pattern
+    c.get_virtual_interfaces_skip.return_value = 'False'
+    c.get_network_interfaces_skip_pattern.return_value = "^etc\d*$"
+    hostinfo = HostInfo(c)
+    network_info = hostinfo.get_network_info()
+
+    self.assertEqual(network_info, {})
+
+    #skip one by pattern
+    c.get_network_interfaces_skip_pattern.return_value = "^etc\d{1}$"
+    hostinfo = HostInfo(c)
+    network_info = hostinfo.get_network_info()
+
+    self.assertEqual(len(network_info), 4)
+
+    all_net_stats = { 'etc2' : net_stats }
+    net_io_counters.return_value = all_net_stats
+    c.get_network_interfaces_skip_pattern.return_value = "^etc\d{1}$"
+    hostinfo = HostInfo(c)
+    network_info = hostinfo.get_network_info()
+
+    self.assertEqual(network_info, {})
+
+    #skip by 'None' pattern
+    c.get_network_interfaces_skip_pattern.return_value = "None"
+    hostinfo = HostInfo(c)
+    network_info = hostinfo.get_network_info()
+
+    self.assertEqual(len(network_info), 4)
+
+  @patch.object(HostInfo, "get_virtual_network_interfaces", new = 
MagicMock(return_value = ['etc11', 'etc2']))
+  @patch("psutil.net_io_counters")
+  def test_get_network_info_skip_by_pattern_and_virtual(self, net_io_counters):
+    Stats = collections.namedtuple('interface', ['bytes_sent', 'bytes_recv',
+                                                  'packets_sent', 
'packets_recv'
+                                                  ])
+
+    net_stats = Stats(bytes_sent = 0, bytes_recv = 1,
+                          packets_sent = 2, packets_recv = 3
+    )
+
+    all_net_stats = { 'etc11' : net_stats, 'etc2' : net_stats, 'etc333' : 
net_stats }
+    net_io_counters.return_value = all_net_stats
+
+    c = MagicMock()
+
+    #skip only one by pattern and other as virtual
+    c.get_virtual_interfaces_skip.return_value = 'True'
+    c.get_network_interfaces_skip_pattern.return_value = "^etc\d{3}$"
+    hostinfo = HostInfo(c)
+    network_info = hostinfo.get_network_info()
+
+    self.assertEqual(network_info, {})
+
+  @patch("os.path.isdir")
+  @patch("os.listdir")
+  @patch("os.readlink")
+  @patch("os.path.islink")
+  def test_get_virtual_network_interfaces(self, islink, readlink, listdir, 
isdir):
+    hostinfo = HostInfo(MagicMock())
+
+    #virtual net device is present
+    isdir.return_value = True
+    listdir.return_value = ['virtual_net_dev']
+    readlink.return_value = "../..devices/virtual/int6"
+    islink.return_value = True
+
+    virtual_net_devices = hostinfo.get_virtual_network_interfaces()
+    self.assertEqual(virtual_net_devices, ['virtual_net_dev'])
+
+    #virtual net device is not present
+    isdir.return_value = True
+    listdir.return_value = ['virtual_net_dev']
+    readlink.return_value = "../..devices/pp01.000/virtio1/int6"
+    islink.return_value = True
+
+    virtual_net_devices = hostinfo.get_virtual_network_interfaces()
+    self.assertEqual(virtual_net_devices, [])
+
+    #symlinks not present
+    isdir.return_value = True
+    listdir.return_value = ['virtual_net_dev']
+    readlink.return_value = "../..devices/virtual/int6"
+    islink.return_value = False
+
+    virtual_net_devices = hostinfo.get_virtual_network_interfaces()
+    self.assertEqual(virtual_net_devices, [])
+
+    #sysfs not available
+    isdir.return_value = False
+    virtual_net_devices = hostinfo.get_virtual_network_interfaces()
+
+    self.assertEqual(virtual_net_devices, [])
+
 
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/db3c09bb/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/configuration/ams-env.xml
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/configuration/ams-env.xml
 
b/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/configuration/ams-env.xml
index a33656e..d79e357 100644
--- 
a/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/configuration/ams-env.xml
+++ 
b/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/configuration/ams-env.xml
@@ -101,6 +101,22 @@
     <on-ambari-upgrade add="true"/>
   </property>
   <property>
+    <name>timeline.metrics.skip.network.interfaces.patterns</name>
+    <value>None</value>
+    <description>
+      Comma separated list of network interfaces to be ignored while 
collecting network metrics
+    </description>
+    <on-ambari-upgrade add="true"/>
+  </property>
+  <property>
+    <name>timeline.metrics.skip.virtual.interfaces</name>
+    <value>false</value>
+    <description>
+      Skips virtual network interfaces while collecting network metrics
+    </description>
+    <on-ambari-upgrade add="true"/>
+  </property>
+  <property>
     <name>content</name>
     <display-name>ams-env template</display-name>
     <value>

http://git-wip-us.apache.org/repos/asf/ambari/blob/db3c09bb/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/scripts/params.py
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/scripts/params.py
 
b/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/scripts/params.py
index fcfe088..5672ee5 100644
--- 
a/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/scripts/params.py
+++ 
b/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/scripts/params.py
@@ -18,23 +18,24 @@ limitations under the License.
 
 """
 
-from functions import calc_xmn_from_xms
-from functions import check_append_heap_property
-from functions import trim_heap_property
+import ConfigParser
+import os
+
+from ambari_commons import OSCheck
+from ambari_commons.ambari_metrics_helper import 
select_metric_collector_hosts_from_hostnames
 from resource_management.core.logger import Logger
-from resource_management.libraries.script.script import Script
-from resource_management.libraries.functions.get_not_managed_resources import 
get_not_managed_resources
 from resource_management.libraries import functions
-from resource_management.libraries.functions.expect import expect
 from resource_management.libraries.functions.default import default
+from resource_management.libraries.functions.expect import expect
 from resource_management.libraries.functions.format import format
+from resource_management.libraries.functions.get_not_managed_resources import 
get_not_managed_resources
 from resource_management.libraries.functions.substitute_vars import 
substitute_vars
 from resource_management.libraries.resources.hdfs_resource import HdfsResource
-from ambari_commons.ambari_metrics_helper import 
select_metric_collector_hosts_from_hostnames
+
 import status_params
-from ambari_commons import OSCheck
-import ConfigParser
-import os
+from functions import calc_xmn_from_xms
+from functions import check_append_heap_property
+from functions import trim_heap_property
 
 if OSCheck.is_windows_family():
   from params_windows import *
@@ -204,6 +205,8 @@ metrics_collector_heapsize = 
default('/configurations/ams-env/metrics_collector_
 metrics_report_interval = 
default("/configurations/ams-site/timeline.metrics.sink.report.interval", 60)
 metrics_collection_period = 
default("/configurations/ams-site/timeline.metrics.sink.collection.period", 10)
 skip_disk_metrics_patterns = 
default("/configurations/ams-env/timeline.metrics.skip.disk.metrics.patterns", 
None)
+skip_network_interfaces_patterns = 
default("/configurations/ams-env/timeline.metrics.skip.network.interfaces.patterns",
 None)
+skip_virtual_interfaces = 
default("/configurations/ams-env/timeline.metrics.skip.virtual.interfaces", 
False)
 
 hbase_log_dir = config['configurations']['ams-hbase-env']['hbase_log_dir']
 hbase_classpath_additional = 
default("/configurations/ams-hbase-env/hbase_classpath_additional", None)

http://git-wip-us.apache.org/repos/asf/ambari/blob/db3c09bb/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/templates/metric_monitor.ini.j2
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/templates/metric_monitor.ini.j2
 
b/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/templates/metric_monitor.ini.j2
index 3823912..1505f9b 100644
--- 
a/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/templates/metric_monitor.ini.j2
+++ 
b/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/templates/metric_monitor.ini.j2
@@ -23,6 +23,8 @@ metrics_servers = {{ams_collector_hosts}}
 enable_time_threshold = false
 enable_value_threshold = false
 skip_disk_patterns = {{skip_disk_metrics_patterns}}
+skip_virtual_interfaces = {{skip_virtual_interfaces}}
+skip_network_interfaces_patterns = {{skip_network_interfaces_patterns}}
 
 [emitter]
 send_interval = {{metrics_report_interval}}

Reply via email to