AMBARI-17898. Add Kerberos HTTP SPNEGO authentication support to Ambari Metrics 
Monitor.  (Qin Liu via Eric Yang)


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

Branch: refs/heads/feature-branch-AMBARI-21307
Commit: d260c89263ee0471514b4cfb8ce938134eceea12
Parents: 6de8094
Author: Eric Yang <ey...@apache.org>
Authored: Mon Aug 21 20:57:34 2017 -0700
Committer: Eric Yang <ey...@apache.org>
Committed: Mon Aug 21 20:57:34 2017 -0700

----------------------------------------------------------------------
 .../conf/unix/metric_monitor.ini                |   2 +
 .../src/main/python/core/config_reader.py       |   8 +
 .../src/main/python/core/emitter.py             |  58 ++++++-
 .../src/main/python/core/krberr.py              |  42 +++++
 .../main/python/core/spnego_kerberos_auth.py    | 164 +++++++++++++++++++
 .../src/test/python/core/TestEmitter.py         |  24 +++
 .../AMBARI_METRICS/0.1.0/kerberos.json          |  26 +++
 .../AMBARI_METRICS/0.1.0/metainfo.xml           |   8 +
 .../AMBARI_METRICS/0.1.0/package/scripts/ams.py |  33 +++-
 .../0.1.0/package/scripts/params.py             |   7 +-
 .../package/templates/metric_monitor.ini.j2     |   2 +
 11 files changed, 360 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/d260c892/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 7fe7397..38fff1e 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
@@ -27,6 +27,8 @@ skip_network_interfaces_patterns =
 
 [emitter]
 send_interval = 60
+kinit_cmd = /usr/bin/kinit -kt /etc/security/keytabs/ams.monitor.keytab 
amsmon/localhost
+klist_cmd = /usr/bin/klist
 
 [collector]
 collector_sleep_interval = 5

http://git-wip-us.apache.org/repos/asf/ambari/blob/d260c892/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 d1429ed..017ad24 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
@@ -115,6 +115,8 @@ enable_value_threshold = false
 
 [emitter]
 send_interval = 60
+kinit_cmd = /usr/bin/kinit -kt /etc/security/keytabs/ams.monitor.keytab 
amsmon/localhost
+klist_cmd = /usr/bin/klist
 
 [collector]
 collector_sleep_interval = 5
@@ -218,6 +220,12 @@ class Configuration:
   def get_send_interval(self):
     return int(self.get("emitter", "send_interval", 60))
 
+  def get_kinit_cmd(self):
+    return self.get("emitter", "kinit_cmd")
+
+  def get_klist_cmd(self):
+    return self.get("emitter", "klist_cmd")
+
   def get_collector_sleep_interval(self):
     return int(self.get("collector", "collector_sleep_interval", 10))
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/d260c892/ambari-metrics/ambari-metrics-host-monitoring/src/main/python/core/emitter.py
----------------------------------------------------------------------
diff --git 
a/ambari-metrics/ambari-metrics-host-monitoring/src/main/python/core/emitter.py 
b/ambari-metrics/ambari-metrics-host-monitoring/src/main/python/core/emitter.py
index 77b8c23..f19434d 100644
--- 
a/ambari-metrics/ambari-metrics-host-monitoring/src/main/python/core/emitter.py
+++ 
b/ambari-metrics/ambari-metrics-host-monitoring/src/main/python/core/emitter.py
@@ -24,6 +24,7 @@ import threading
 from security import CachedHTTPSConnection, CachedHTTPConnection
 from blacklisted_set import BlacklistedSet
 from config_reader import ROUND_ROBIN_FAILOVER_STRATEGY
+from spnego_kerberos_auth import SPNEGOKerberosAuth
 
 logger = logging.getLogger()
 
@@ -31,6 +32,10 @@ class Emitter(threading.Thread):
   AMS_METRICS_POST_URL = "/ws/v1/timeline/metrics/"
   RETRY_SLEEP_INTERVAL = 5
   MAX_RETRY_COUNT = 3
+  cookie_cached = {}
+  kinit_cmd = None
+  klist_cmd = None
+  spnego_krb_auth = None
   """
   Wake up every send interval seconds and empty the application metric map.
   """
@@ -39,6 +44,10 @@ class Emitter(threading.Thread):
     logger.debug('Initializing Emitter thread.')
     self.lock = threading.Lock()
     self.send_interval = config.get_send_interval()
+    self.kinit_cmd = config.get_kinit_cmd()
+    if self.kinit_cmd:
+      logger.debug(self.kinit_cmd)
+    self.klist_cmd = config.get_klist_cmd()
     self.hostname = config.get_hostname_config()
     self.hostname_hash = self.compute_hash(self.hostname)
     self._stop_handler = stop_handler
@@ -71,6 +80,7 @@ class Emitter(threading.Thread):
         self.submit_metrics()
       except Exception, e:
         logger.warn('Unable to emit events. %s' % str(e))
+        self.cookie_cached = {}
       pass
       #Wait for the service stop event instead of sleeping blindly
       if 0 == self._stop_handler.wait(self.send_interval):
@@ -108,17 +118,50 @@ class Emitter(threading.Thread):
     headers = {"Content-Type" : "application/json", "Accept" : "*/*"}
     connection = self.get_connection(collector_host)
     logger.debug("message to send: %s" % data)
+
+    try:
+      if self.cookie_cached[connection.host]:
+        headers["Cookie"] = self.cookie_cached[connection.host]
+        logger.debug("Cookie: %s" % self.cookie_cached[connection.host])
+    except Exception, e:
+      self.cookie_cached = {}
+    pass
+
     retry_count = 0
     while retry_count < self.MAX_RETRY_COUNT:
       response = self.get_response_from_submission(connection, data, headers)
-      if response and response.status == 200:
-        return True
-      else:
-        logger.warn("Retrying after {0} ...".format(self.RETRY_SLEEP_INTERVAL))
-        retry_count += 1
-        #Wait for the service stop event instead of sleeping blindly
-        if 0 == self._stop_handler.wait(self.RETRY_SLEEP_INTERVAL):
+      if response:
+        if response.status == 200:
           return True
+        if response.status == 401:
+          self.cookie_cached = {}
+          auth_header = response.getheader('www-authenticate', None)
+          if auth_header == None:
+              logger.warn('www-authenticate header not found')
+          else:
+            self.spnego_krb_auth = SPNEGOKerberosAuth()
+            if self.spnego_krb_auth.get_negotiate_value(auth_header) == '':
+              response = 
self.spnego_krb_auth.authenticate_handshake(connection, "POST", 
self.AMS_METRICS_POST_URL, data, headers, self.kinit_cmd, self.klist_cmd)
+              if response:
+                logger.debug("response from authenticate_client: retcode = 
{0}, reason = {1}"
+                              .format(response.status, response.reason))
+                logger.debug(str(response.read()))
+                if response.status == 200:
+                  logger.debug("response headers: 
{0}".format(response.getheaders()))
+                  logger.debug("cookie_cached: %s" % self.cookie_cached)
+                  set_cookie_header = response.getheader('set-cookie', None)
+                  if set_cookie_header and self.spnego_krb_auth:
+                    set_cookie_val = 
self.spnego_krb_auth.get_hadoop_auth_cookie(set_cookie_header)
+                    logger.debug("set_cookie: %s" % set_cookie_val)
+                    if set_cookie_val:
+                      self.cookie_cached[connection.host] = set_cookie_val
+                  return True
+      #No response or failed
+      logger.warn("Retrying after {0} ...".format(self.RETRY_SLEEP_INTERVAL))
+      retry_count += 1
+      #Wait for the service stop event instead of sleeping blindly
+      if 0 == self._stop_handler.wait(self.RETRY_SLEEP_INTERVAL):
+        return True
     pass
 
     if retry_count >= self.MAX_RETRY_COUNT:
@@ -150,6 +193,7 @@ class Emitter(threading.Thread):
       return response
     except Exception, e:
       logger.warn('Error sending metrics to server. %s' % str(e))
+      self.cookie_cached = {}
       return None
 
   def get_collector_host_shard(self):

http://git-wip-us.apache.org/repos/asf/ambari/blob/d260c892/ambari-metrics/ambari-metrics-host-monitoring/src/main/python/core/krberr.py
----------------------------------------------------------------------
diff --git 
a/ambari-metrics/ambari-metrics-host-monitoring/src/main/python/core/krberr.py 
b/ambari-metrics/ambari-metrics-host-monitoring/src/main/python/core/krberr.py
new file mode 100644
index 0000000..c5e0163
--- /dev/null
+++ 
b/ambari-metrics/ambari-metrics-host-monitoring/src/main/python/core/krberr.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+
+'''
+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.
+'''
+
+"""
+Python Kerberos GSS APIs used by spnego_kerberos_auth.py.
+It is used as a place holder for kerberos.py which is not available.
+"""
+
+class KrbError(Exception):
+  pass
+
+class GSSError(KrbError):
+  pass
+
+def authGSSClientInit(service):
+  pass
+
+def authGSSClientClean(context):
+  pass
+
+def authGSSClientStep(context, challenge):
+  pass
+
+def authGSSClientResponse(context):
+  pass

http://git-wip-us.apache.org/repos/asf/ambari/blob/d260c892/ambari-metrics/ambari-metrics-host-monitoring/src/main/python/core/spnego_kerberos_auth.py
----------------------------------------------------------------------
diff --git 
a/ambari-metrics/ambari-metrics-host-monitoring/src/main/python/core/spnego_kerberos_auth.py
 
b/ambari-metrics/ambari-metrics-host-monitoring/src/main/python/core/spnego_kerberos_auth.py
new file mode 100644
index 0000000..e49712f
--- /dev/null
+++ 
b/ambari-metrics/ambari-metrics-host-monitoring/src/main/python/core/spnego_kerberos_auth.py
@@ -0,0 +1,164 @@
+#!/usr/bin/env python
+
+'''
+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.
+'''
+
+import logging
+import httplib
+import os
+
+logger = logging.getLogger()
+try:
+  import kerberos
+except ImportError:
+  import krberr as kerberos
+  logger.warn('import kerberos exception: %s' % str(ImportError))
+pass
+
+class SPNEGOKerberosAuth:
+  def __init__(self):
+    self.krb_context = None
+
+  def authenticate_handshake (self, connection, method, service_url, body, 
headers, kinit_cmd, klist_cmd):
+    # kinit to ensure ticket valid
+    self.execute_kinit(kinit_cmd, klist_cmd)
+
+    try:
+      # Authenticate the client request
+      response = self.authenticate_client(connection, method, service_url, 
body, headers)
+
+      # Authenticate the response from the server
+      if response:
+        self.authenticate_server(response)
+      return response
+    finally:
+      # Clean the client context after the handshake
+      self.clean_client_context()
+    pass
+
+  def execute_kinit(self, kinit_cmd, klist_cmd):
+    exit_status = os.system(kinit_cmd)
+    logger.debug("kinit exit_status: {0}".format(exit_status))
+    logger.debug(os.system(klist_cmd))
+    return exit_status
+
+  def authenticate_client(self, connection, method, service_url, body, 
headers):
+    service = "HTTP@%s" % connection.host.lower()
+    logger.debug("connection: %s", connection)
+    logger.debug("service: %s", service)
+
+    auth_header = self.get_authorization_header(service)
+    logger.debug("Authorization: %s" % auth_header)
+
+    # Send 2nd HTTP request with authorization header
+    headers['Authorization'] = auth_header
+    try:
+      connection.request(method, service_url, body, headers)
+      response = connection.getresponse()
+    except Exception, e:
+      logger.warn('2nd HTTP request exception from server: %s' % str(e))
+      return None
+    pass
+    if response:
+      logger.debug("2nd HTTP response from server: retcode = {0}, reason = {1}"
+                    .format(response.status, response.reason))
+      logger.debug(str(response.read()))
+      logger.debug("response headers: {0}".format(response.getheaders()))
+    return response
+
+  def get_authorization_header(self, service):
+    # Initialize the context object for client-side authentication with a 
service principal
+    try:
+      result, self.krb_context = kerberos.authGSSClientInit(service)
+      if result == -1:
+        logger.warn('authGSSClientInit result: {0}'.format(result))
+        return None
+    except kerberos.GSSError, e:
+      logger.warn('authGSSClientInit exception: %s' % str(e))
+      return None
+    pass
+
+    # Process the first client-side step with the context
+    try:
+      result = kerberos.authGSSClientStep(self.krb_context, "")
+      if result == -1:
+        logger.warn('authGSSClientStep result for authenticate client: 
{0}'.format(result))
+        return None
+    except kerberos.GSSError, e:
+      logger.warn('authGSSClientStep exception for authenticate client: %s' % 
str(e))
+      return None
+    pass
+
+    # Get the client response from the first client-side step
+    try:
+      negotiate_value = kerberos.authGSSClientResponse(self.krb_context)
+      logger.debug("authGSSClientResponse 
response:{0}".format(negotiate_value))
+    except kerberos.GSSError, e:
+      logger.warn('authGSSClientResponse exception: %s' % str(e))
+      return None
+    pass
+
+    # Build the authorization header
+    return "Negotiate %s" % negotiate_value
+
+  def authenticate_server(self, response):
+    auth_header = response.getheader('www-authenticate', None)
+    negotiate_value = self.get_negotiate_value(auth_header)
+    if negotiate_value == None:
+      logger.warn('www-authenticate header not found')
+
+    # Process the client-side step with the context and the negotiate value 
from 2nd HTTP response
+    try:
+      result = kerberos.authGSSClientStep(self.krb_context, negotiate_value)
+      if result == -1:
+        logger.warn('authGSSClientStep result for authenticate server: 
{0}'.format(result))
+    except kerberos.GSSError, e:
+      logger.warn('authGSSClientStep exception for authenticate server: %s' % 
str(e))
+      result = -1
+    pass
+    return result
+
+  def clean_client_context(self):
+    # Destroy the context for client-side authentication
+    try:
+      result = kerberos.authGSSClientClean(self.krb_context)
+      logger.debug("authGSSClientClean result:{0}".format(result))
+    except kerberos.GSSError, e:
+      logger.warn('authGSSClientClean exception: %s' % str(e))
+      result = -1
+    pass
+    return result
+
+  def get_hadoop_auth_cookie(self, set_cookie_header):
+    if set_cookie_header:
+      for field in set_cookie_header.split(";"):
+        if field.startswith('hadoop.auth='):
+          return field
+      else:
+        return None
+    return None
+
+  def get_negotiate_value(self, auth_header):
+    if auth_header:
+      for field in auth_header.split(","):
+        key, __, value = field.strip().partition(" ")
+        if key.lower() == "negotiate":
+          return value.strip()
+      else:
+        return None
+    return None

http://git-wip-us.apache.org/repos/asf/ambari/blob/d260c892/ambari-metrics/ambari-metrics-host-monitoring/src/test/python/core/TestEmitter.py
----------------------------------------------------------------------
diff --git 
a/ambari-metrics/ambari-metrics-host-monitoring/src/test/python/core/TestEmitter.py
 
b/ambari-metrics/ambari-metrics-host-monitoring/src/test/python/core/TestEmitter.py
index 4056ae3..8b3eb66 100644
--- 
a/ambari-metrics/ambari-metrics-host-monitoring/src/test/python/core/TestEmitter.py
+++ 
b/ambari-metrics/ambari-metrics-host-monitoring/src/test/python/core/TestEmitter.py
@@ -27,6 +27,7 @@ from only_for_platform import get_platform, PLATFORM_WINDOWS
 from mock.mock import patch, MagicMock
 from security import CachedHTTPConnection
 from blacklisted_set import BlacklistedSet
+from spnego_kerberos_auth import SPNEGOKerberosAuth
 
 if get_platform() != PLATFORM_WINDOWS:
   os_distro_value = ('Suse','11','Final')
@@ -86,6 +87,29 @@ class TestEmitter(TestCase):
     self.assertEqual(request_mock.call_count, 3)
     self.assertUrlData(request_mock)
 
+  @patch.object(OSCheck, "os_distribution", new = MagicMock(return_value = 
os_distro_value))
+  @patch.object(CachedHTTPConnection, "create_connection", new = MagicMock())
+  @patch.object(SPNEGOKerberosAuth, "authenticate_handshake")
+  @patch.object(CachedHTTPConnection, "getresponse")
+  @patch.object(CachedHTTPConnection, "request")
+  def test_spnego_negotiation(self, request_mock, getresponse_mock, auth_mock):
+    request_mock.return_value = MagicMock()
+    getresponse_mock.return_value.status = 401
+    getresponse_mock.return_value.getheader.return_value = "Negotiate   "
+
+    auth_mock.return_value.status = 200
+
+    stop_handler = bind_signal_handlers()
+
+    config = Configuration()
+    application_metric_map = ApplicationMetricMap("host","10.10.10.10")
+    application_metric_map.clear()
+    application_metric_map.put_metric("APP1", {"metric1":1}, 1)
+    emitter = Emitter(config, application_metric_map, stop_handler)
+    emitter.submit_metrics()
+
+
+    self.assertEqual(request_mock.call_count, 1)
   def assertUrlData(self, request_mock):
     self.assertEqual(len(request_mock.call_args), 2)
     data = request_mock.call_args[0][2]

http://git-wip-us.apache.org/repos/asf/ambari/blob/d260c892/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/kerberos.json
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/kerberos.json
 
b/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/kerberos.json
index 51f541f..a6afda5 100644
--- 
a/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/kerberos.json
+++ 
b/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/kerberos.json
@@ -9,6 +9,32 @@
       ],
       "components": [
         {
+          "name": "METRICS_MONITOR",
+          "identities": [
+            {
+              "name": "ams_monitor",
+              "principal": {
+                "value": "amsmon/_HOST@${realm}",
+                "type": "service",
+                "configuration": 
"ams-hbase-security-site/ams.monitor.principal",
+                "local_username": "${ams-env/ambari_metrics_user}"
+              },
+              "keytab": {
+                "file": "${keytab_dir}/ams-monitor.keytab",
+                "owner": {
+                  "name": "${ams-env/ambari_metrics_user}",
+                  "access": "r"
+                },
+                "group": {
+                  "name": "${cluster-env/user_group}",
+                  "access": ""
+                },
+                "configuration": "ams-hbase-security-site/ams.monitor.keytab"
+              }
+            }
+          ]
+        },
+        {
           "name": "METRICS_COLLECTOR",
           "identities": [
             {

http://git-wip-us.apache.org/repos/asf/ambari/blob/d260c892/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/metainfo.xml
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/metainfo.xml
 
b/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/metainfo.xml
index 9031b46..43c3685 100644
--- 
a/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/metainfo.xml
+++ 
b/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/metainfo.xml
@@ -151,6 +151,14 @@
           </packages>
         </osSpecific>
         <osSpecific>
+          <osFamily>redhat7,redhat6,centos6,centos7</osFamily>
+          <packages>
+            <package>
+              <name>python-kerberos</name>
+            </package>
+          </packages>
+        </osSpecific>
+        <osSpecific>
           <osFamily>debian7,ubuntu12,ubuntu14</osFamily>
           <packages>
             <package>

http://git-wip-us.apache.org/repos/asf/ambari/blob/d260c892/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/scripts/ams.py
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/scripts/ams.py
 
b/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/scripts/ams.py
index f49d47d..9a31ade 100644
--- 
a/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/scripts/ams.py
+++ 
b/ambari-server/src/main/resources/common-services/AMBARI_METRICS/0.1.0/package/scripts/ams.py
@@ -334,14 +334,12 @@ def ams(name=None, action=None):
             mode=0644
       )
 
-      # Remove spnego configs from core-site, since AMS does not support 
spnego (AMBARI-14384)
+      # Remove spnego configs from core-site if platform does not have 
python-kerberos library
       truncated_core_site = {}
       truncated_core_site.update(params.config['configurations']['core-site'])
-      if 'core-site' in params.config['configurations']:
-        if 'hadoop.http.authentication.type' in 
params.config['configurations']['core-site']:
-          truncated_core_site.pop('hadoop.http.authentication.type')
-        if 'hadoop.http.filter.initializers' in 
params.config['configurations']['core-site']:
-          truncated_core_site.pop('hadoop.http.filter.initializers')
+      if is_spnego_enabled(params) and is_redhat_centos_6_plus() == False:
+        truncated_core_site.pop('hadoop.http.authentication.type')
+        truncated_core_site.pop('hadoop.http.filter.initializers')
 
       XmlConfig("core-site.xml",
                 conf_dir=params.ams_collector_conf_dir,
@@ -367,6 +365,13 @@ def ams(name=None, action=None):
     pass
 
   elif name == 'monitor':
+
+    if is_spnego_enabled(params) and is_redhat_centos_6_plus():
+      try:
+        import kerberos
+      except ImportError:
+        raise ImportError("python-kerberos package need to be installed to run 
AMS in SPNEGO mode")
+
     Directory(params.ams_monitor_conf_dir,
               owner=params.ams_user,
               group=params.user_group,
@@ -481,6 +486,22 @@ def ams(name=None, action=None):
 
     pass
 
+def is_spnego_enabled(params):
+  if 'core-site' in params.config['configurations'] \
+      and 'hadoop.http.authentication.type' in 
params.config['configurations']['core-site'] \
+      and 
params.config['configurations']['core-site']['hadoop.http.authentication.type'] 
== "kerberos" \
+      and 'hadoop.http.filter.initializers' in 
params.config['configurations']['core-site'] \
+      and 
params.config['configurations']['core-site']['hadoop.http.filter.initializers'] 
== "org.apache.hadoop.security.AuthenticationFilterInitializer":
+    return True
+  return False
+
+def is_redhat_centos_6_plus():
+  import platform
+
+  if platform.dist()[0] in ['redhat', 'centos'] and platform.dist()[1] > '6.0':
+    return True
+  return False
+
 def export_ca_certs(dir_path):
   # export ca certificates on every restart to handle changed truststore 
content
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/d260c892/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 486f568..6975bec 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
@@ -304,7 +304,10 @@ service_check_data = functions.get_unique_id_and_date()
 user_group = config['configurations']['cluster-env']["user_group"]
 hadoop_user = "hadoop"
 
+kinit_path_local = 
functions.get_kinit_path(default('/configurations/kerberos-env/executable_search_paths',
 None))
 kinit_cmd = ""
+klist_path_local = 
functions.get_klist_path(default('/configurations/kerberos-env/executable_search_paths',
 None))
+klist_cmd = ""
 
 if security_enabled:
   _hostname_lowercase = config['hostname'].lower()
@@ -328,6 +331,9 @@ if security_enabled:
   regionserver_keytab_path = 
config['configurations']['ams-hbase-security-site']['hbase.regionserver.keytab.file']
   regionserver_jaas_princ = 
config['configurations']['ams-hbase-security-site']['hbase.regionserver.kerberos.principal'].replace('_HOST',_hostname_lowercase)
 
+  kinit_cmd = '%s -kt %s %s' % (kinit_path_local, 
config['configurations']['ams-hbase-security-site']['ams.monitor.keytab'], 
config['configurations']['ams-hbase-security-site']['ams.monitor.principal'].replace('_HOST',_hostname_lowercase))
+  klist_cmd = '%s' % klist_path_local
+
 #Ambari metrics log4j settings
 ams_hbase_log_maxfilesize = 
default('configurations/ams-hbase-log4j/ams_hbase_log_maxfilesize',256)
 ams_hbase_log_maxbackupindex = 
default('configurations/ams-hbase-log4j/ams_hbase_log_maxbackupindex',20)
@@ -362,7 +368,6 @@ if hbase_wal_dir and re.search("^file://|/", 
hbase_wal_dir): #If wal dir is on l
 hdfs_user_keytab = config['configurations']['hadoop-env']['hdfs_user_keytab']
 hdfs_user = config['configurations']['hadoop-env']['hdfs_user']
 hdfs_principal_name = 
config['configurations']['hadoop-env']['hdfs_principal_name']
-kinit_path_local = 
functions.get_kinit_path(default('/configurations/kerberos-env/executable_search_paths',
 None))
 
 
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/d260c892/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 b7dee50..245ba3b 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
@@ -30,6 +30,8 @@ set.instanceId={{set_instanceId}}
 
 [emitter]
 send_interval = {{metrics_report_interval}}
+kinit_cmd = {{kinit_cmd}}
+klist_cmd = {{klist_cmd}}
 
 [collector]
 collector_sleep_interval = 10

Reply via email to