Repository: ambari
Updated Branches:
  refs/heads/trunk 27f763450 -> 6bbed2779


AMBARI-9586 - Alerts: WEB type alerts fail in Kerberos secured cluster (Yurii 
Shylov via jonathanhurley)


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

Branch: refs/heads/trunk
Commit: 6bbed2779d05ef11294239f746abc40961fd83f7
Parents: 27f7634
Author: Jonathan Hurley <jhur...@hortonworks.com>
Authored: Fri Feb 13 12:08:19 2015 -0500
Committer: Jonathan Hurley <jhur...@hortonworks.com>
Committed: Fri Feb 13 12:08:19 2015 -0500

----------------------------------------------------------------------
 .../python/ambari_agent/alerts/base_alert.py    | 13 ++++-
 .../python/ambari_agent/alerts/web_alert.py     | 55 ++++++++++++++++----
 .../src/test/python/ambari_agent/TestAlerts.py  | 16 +++---
 .../ambari/server/state/alert/AlertUri.java     | 30 +++++++++++
 .../FALCON/0.5.0.2.1/alerts.json                |  6 ++-
 .../common-services/HDFS/2.1.0.2.0/alerts.json  | 12 +++--
 .../common-services/OOZIE/4.0.0.2.0/alerts.json |  6 ++-
 .../common-services/STORM/0.9.1.2.1/alerts.json |  6 ++-
 .../common-services/YARN/2.1.0.2.0/alerts.json  | 24 ++++++---
 9 files changed, 129 insertions(+), 39 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/6bbed277/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py 
b/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
index 0b49b9b..2f2c997 100644
--- a/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
+++ b/ambari-agent/src/main/python/ambari_agent/alerts/base_alert.py
@@ -212,6 +212,8 @@ class BaseAlert(object):
     https_property_key = None
     https_property_value_key = None
     default_port = None
+    kerberos_keytab = None
+    kerberos_principal = None
     
     if 'http' in uri_structure:
       http_key = self._find_lookup_property(uri_structure['http'])
@@ -228,12 +230,19 @@ class BaseAlert(object):
     if 'default_port' in uri_structure:
       default_port = uri_structure['default_port']
 
+    if 'kerberos_keytab' in uri_structure:
+      kerberos_keytab = 
self._find_lookup_property(uri_structure['kerberos_keytab'])
+
+    if 'kerberos_principal' in uri_structure:
+      kerberos_principal = 
self._find_lookup_property(uri_structure['kerberos_principal'])
+
     AlertUriLookupKeys = namedtuple('AlertUriLookupKeys', 
-        'http https https_property https_property_value default_port')
+        'http https https_property https_property_value default_port 
kerberos_keytab kerberos_principal')
     
     alert_uri_lookup_keys = AlertUriLookupKeys(http=http_key, https=https_key, 
         https_property=https_property_key, 
-        https_property_value=https_property_value_key, 
default_port=default_port)
+        https_property_value=https_property_value_key, 
default_port=default_port,
+        kerberos_keytab=kerberos_keytab, kerberos_principal=kerberos_principal)
     
     return alert_uri_lookup_keys
 

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bbed277/ambari-agent/src/main/python/ambari_agent/alerts/web_alert.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/main/python/ambari_agent/alerts/web_alert.py 
b/ambari-agent/src/main/python/ambari_agent/alerts/web_alert.py
index fa578ce..8ee6606 100644
--- a/ambari-agent/src/main/python/ambari_agent/alerts/web_alert.py
+++ b/ambari-agent/src/main/python/ambari_agent/alerts/web_alert.py
@@ -20,7 +20,9 @@ limitations under the License.
 
 import logging
 import time
-import urllib2
+import subprocess
+import os
+
 from alerts.base_alert import BaseAlert
 from collections import namedtuple
 from resource_management.libraries.functions.get_port_from_url import 
get_port_from_url
@@ -29,6 +31,8 @@ from ambari_commons.inet_utils import resolve_address
 
 logger = logging.getLogger()
 
+CURL_CONNECTION_TIMEOUT = '20'
+
 class WebAlert(BaseAlert):
   
   def __init__(self, alert_meta, alert_source_meta):
@@ -55,9 +59,10 @@ class WebAlert(BaseAlert):
     web_response = self._make_web_request(url)
     status_code = web_response.status_code
     time_seconds = web_response.time_millis / 1000
+    error_message = web_response.error_msg
 
     if status_code == 0:
-      return (self.RESULT_CRITICAL, [status_code, url, time_seconds])
+      return (self.RESULT_CRITICAL, [status_code, url, time_seconds, 
error_message])
     
     if status_code < 400:
       return (self.RESULT_OK, [status_code, url, time_seconds])
@@ -106,21 +111,49 @@ class WebAlert(BaseAlert):
     Makes an http(s) request to a web resource and returns the http code. If
     there was an error making the request, return 0 for the status code.
     """    
-    WebResponse = namedtuple('WebResponse', 'status_code time_millis')
+    WebResponse = namedtuple('WebResponse', 'status_code time_millis 
error_msg')
     
     time_millis = 0
     
     try:
-      start_time = time.time()      
-      response = urllib2.urlopen(url)
+      kerberos_keytab = None
+      kerberos_principal = None
+
+      if self.uri_property_keys.kerberos_principal is not None:
+        kerberos_principal = self._lookup_property_value(
+          self.uri_property_keys.kerberos_principal)
+
+        if kerberos_principal is not None:
+          # substitute _HOST in kerberos principal with actual fqdn
+          kerberos_principal = kerberos_principal.replace('_HOST', 
self.host_name)
+
+      if self.uri_property_keys.kerberos_keytab is not None:
+        kerberos_keytab = 
self._lookup_property_value(self.uri_property_keys.kerberos_keytab)
+
+      if kerberos_principal is not None and kerberos_keytab is not None:
+        os.system("kinit -kt {0} {1} > /dev/null".format(kerberos_keytab, 
kerberos_principal))
+
+      # substitute 0.0.0.0 in url with actual fqdn
+      url = url.replace('0.0.0.0', self.host_name)
+      start_time = time.time()
+      curl = subprocess.Popen(['curl', '--negotiate', '-u', ':', '-sL', '-w',
+        '%{http_code}', url, '--connect-timeout', CURL_CONNECTION_TIMEOUT,
+        '-o', '/dev/null'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+      out, err = curl.communicate()
+
+      if err != '':
+        raise Exception(err)
+
+      response_code = int(out)
       time_millis = time.time() - start_time
-    except:
+    except Exception, exc:
       if logger.isEnabledFor(logging.DEBUG):
-        logger.exception("[Alert][{0}] Failed to make a web 
request".format(self.get_name()))
-      
-      return WebResponse(status_code=0, time_millis=0)
-    
-    return WebResponse(status_code=response.getcode(), 
time_millis=time_millis) 
+        logger.exception("[Alert][{0}] Unable to make a web 
request.".format(self.get_name()))
+
+      return WebResponse(status_code=0, time_millis=0, error_msg=str(exc))
+
+    return WebResponse(status_code=response_code, time_millis=time_millis, 
error_msg=None)
 
 
   def _get_reporting_text(self, state):

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bbed277/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
----------------------------------------------------------------------
diff --git a/ambari-agent/src/test/python/ambari_agent/TestAlerts.py 
b/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
index 813f478..a04088a 100644
--- a/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
+++ b/ambari-agent/src/test/python/ambari_agent/TestAlerts.py
@@ -419,14 +419,14 @@ class TestAlerts(TestCase):
             "text": "(Unit Tests) warning: {0}",
           },
           "critical": {
-            "text": "(Unit Tests) critical: {1}",
+            "text": "(Unit Tests) critical: {1}. {3}",
           }
         }
       }
     }
 
-    WebResponse = namedtuple('WebResponse', 'status_code time_millis')
-    wa_make_web_request_mock.return_value = WebResponse(200,1.234)
+    WebResponse = namedtuple('WebResponse', 'status_code time_millis 
error_msg')
+    wa_make_web_request_mock.return_value = WebResponse(200,1.234,None)
 
     # run the alert and check HTTP 200    
     collector = AlertCollector()
@@ -437,11 +437,11 @@ class TestAlerts(TestCase):
     alerts = collector.alerts()
     self.assertEquals(0, len(collector.alerts()))
 
-    self.assertEquals('OK', alerts[0]['state'])
     self.assertEquals('(Unit Tests) ok: 200', alerts[0]['text'])
+    self.assertEquals('OK', alerts[0]['state'])
 
     # run the alert and check HTTP 500
-    wa_make_web_request_mock.return_value = WebResponse(500,1.234)
+    wa_make_web_request_mock.return_value = WebResponse(500,1.234,None)
     collector = AlertCollector()
     alert = WebAlert(json, json['source'])
     alert.set_helpers(collector, {'hdfs-site/dfs.datanode.http.address': 
'1.2.3.4:80'})
@@ -454,7 +454,7 @@ class TestAlerts(TestCase):
     self.assertEquals('(Unit Tests) warning: 500', alerts[0]['text'])
 
     # run the alert and check critical
-    wa_make_web_request_mock.return_value = WebResponse(0,0)
+    wa_make_web_request_mock.return_value = WebResponse(0,0,'error message')
      
     collector = AlertCollector()
     alert = WebAlert(json, json['source'])
@@ -466,7 +466,7 @@ class TestAlerts(TestCase):
     
     # http assertion indicating that we properly determined non-SSL
     self.assertEquals('CRITICAL', alerts[0]['state'])
-    self.assertEquals('(Unit Tests) critical: http://1.2.3.4:80', 
alerts[0]['text'])
+    self.assertEquals('(Unit Tests) critical: http://1.2.3.4:80. error 
message', alerts[0]['text'])
      
     collector = AlertCollector()
     alert = WebAlert(json, json['source'])
@@ -482,7 +482,7 @@ class TestAlerts(TestCase):
     
     # SSL assertion
     self.assertEquals('CRITICAL', alerts[0]['state'])
-    self.assertEquals('(Unit Tests) critical: https://1.2.3.4:8443', 
alerts[0]['text'])
+    self.assertEquals('(Unit Tests) critical: https://1.2.3.4:8443. error 
message', alerts[0]['text'])
 
   def test_reschedule(self):
     test_file_path = os.path.join('ambari_agent', 'dummy_files')

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bbed277/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertUri.java
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertUri.java
 
b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertUri.java
index 731e41a..fe592a8 100644
--- 
a/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertUri.java
+++ 
b/ambari-server/src/main/java/org/apache/ambari/server/state/alert/AlertUri.java
@@ -56,6 +56,18 @@ public class AlertUri {
   private String m_httpsPropertyValue;
 
   /**
+   * Kerberos keytab path to use.
+   */
+  @SerializedName("kerberos_keytab")
+  private String m_kerberosKeytab;
+
+  /**
+   * Kerberos principal name to use.
+   */
+  @SerializedName("kerberos_principal")
+  private String m_kerberosPrincipal;
+
+  /**
    * A default port to use on the host running the alert if no URLs can be
    * found.
    */
@@ -115,6 +127,24 @@ public class AlertUri {
   }
 
   /**
+   * The configuration property with kerberos keytab path.
+   *
+   * @return the configuration property, or {@code null} for none.
+   */
+  public String getKerberosKeytab() {
+    return m_kerberosKeytab;
+  }
+
+  /**
+   * The configuration property with kerberos principal name.
+   *
+   * @return the configuration property, or {@code null} for none.
+   */
+  public String getKerberosPrincipal() {
+    return m_kerberosPrincipal;
+  }
+
+  /**
    * {@inheritDoc}
    */
   @Override

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bbed277/ambari-server/src/main/resources/common-services/FALCON/0.5.0.2.1/alerts.json
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/common-services/FALCON/0.5.0.2.1/alerts.json 
b/ambari-server/src/main/resources/common-services/FALCON/0.5.0.2.1/alerts.json
index 7843676..a85787e 100644
--- 
a/ambari-server/src/main/resources/common-services/FALCON/0.5.0.2.1/alerts.json
+++ 
b/ambari-server/src/main/resources/common-services/FALCON/0.5.0.2.1/alerts.json
@@ -38,7 +38,9 @@
           "type": "WEB",
           "uri": {
             "http": "{{falcon-env/falcon_port}}",
-            "default_port": 15000
+            "default_port": 15000,
+            "kerberos_keytab": 
"{{core-site/hadoop.http.authentication.kerberos.keytab}}",
+            "kerberos_principal": 
"{{core-site/hadoop.http.authentication.kerberos.principal}}"
           },
           "reporting": {
             "ok": {
@@ -48,7 +50,7 @@
               "text": "HTTP {0} response in {2:.3f} seconds"
             },
             "critical": {
-              "text": "Connection failed to {1}"
+              "text": "Connection failed to {1}: {3}"
             }
           }
         }

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bbed277/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/alerts.json
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/alerts.json 
b/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/alerts.json
index 6aa7b2c..7b19415 100644
--- 
a/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/alerts.json
+++ 
b/ambari-server/src/main/resources/common-services/HDFS/2.1.0.2.0/alerts.json
@@ -91,7 +91,9 @@
             "http": "{{hdfs-site/dfs.namenode.http-address}}",
             "https": "{{hdfs-site/dfs.namenode.https-address}}",
             "https_property": "{{hdfs-site/dfs.http.policy}}",
-            "https_property_value": "HTTPS_ONLY"
+            "https_property_value": "HTTPS_ONLY",
+            "kerberos_keytab": 
"{{hdfs-site/dfs.web.authentication.kerberos.keytab}}",
+            "kerberos_principal": 
"{{hdfs-site/dfs.web.authentication.kerberos.principal}}"
           },
           "reporting": {
             "ok": {
@@ -101,7 +103,7 @@
               "text": "HTTP {0} response in {2:.3f} seconds"
             },
             "critical": {
-              "text": "Connection failed to {1}"
+              "text": "Connection failed to {1}: {3}"
             }
           }
         }
@@ -482,7 +484,9 @@
             "http": "{{hdfs-site/dfs.datanode.http.address}}",
             "https": "{{hdfs-site/dfs.datanode.https.address}}",
             "https_property": "{{hdfs-site/dfs.http.policy}}",
-            "https_property_value": "HTTPS_ONLY"
+            "https_property_value": "HTTPS_ONLY",
+            "kerberos_keytab": 
"{{hdfs-site/dfs.web.authentication.kerberos.keytab}}",
+            "kerberos_principal": 
"{{hdfs-site/dfs.web.authentication.kerberos.principal}}"
           },
           "reporting": {
             "ok": {
@@ -492,7 +496,7 @@
               "text": "HTTP {0} response in {2:.3f} seconds"
             },
             "critical": {
-              "text": "Connection failed to {1}"
+              "text": "Connection failed to {1}: {3}"
             }
           }
         }

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bbed277/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/alerts.json
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/alerts.json 
b/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/alerts.json
index 3eae69f..a29d793 100644
--- 
a/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/alerts.json
+++ 
b/ambari-server/src/main/resources/common-services/OOZIE/4.0.0.2.0/alerts.json
@@ -11,7 +11,9 @@
         "source": {
           "type": "WEB",
           "uri": {
-            "http": "{{oozie-site/oozie.base.url}}/oozie"
+            "http": "{{oozie-site/oozie.base.url}}/oozie",
+            "kerberos_keytab": 
"{{oozie-site/oozie.authentication.kerberos.keytab}}",
+            "kerberos_principal": 
"{{oozie-site/oozie.authentication.kerberos.principal}}"
           },
           "reporting": {
             "ok": {
@@ -21,7 +23,7 @@
               "text": "HTTP {0} response in {2:.3f} seconds"
             },
             "critical": {
-              "text": "Connection failed to {1}"
+              "text": "Connection failed to {1}: {3}"
             }
           }
         }

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bbed277/ambari-server/src/main/resources/common-services/STORM/0.9.1.2.1/alerts.json
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/common-services/STORM/0.9.1.2.1/alerts.json 
b/ambari-server/src/main/resources/common-services/STORM/0.9.1.2.1/alerts.json
index 4c4e027..abf6b81 100644
--- 
a/ambari-server/src/main/resources/common-services/STORM/0.9.1.2.1/alerts.json
+++ 
b/ambari-server/src/main/resources/common-services/STORM/0.9.1.2.1/alerts.json
@@ -61,7 +61,9 @@
         "source": {
           "type": "WEB",
           "uri": {
-            "http": "{{storm-site/ui.port}}"
+            "http": "{{storm-site/ui.port}}",
+            "kerberos_keytab": 
"{{core-site/hadoop.http.authentication.kerberos.keytab}}",
+            "kerberos_principal": 
"{{core-site/hadoop.http.authentication.kerberos.principal}}"
           },
           "reporting": {
             "ok": {
@@ -71,7 +73,7 @@
               "text": "HTTP {0} response in {2:.3f} seconds"
             },
             "critical": {
-              "text": "Connection failed to {1}"
+              "text": "Connection failed to {1}: {3}"
             }
           }
         }

http://git-wip-us.apache.org/repos/asf/ambari/blob/6bbed277/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/alerts.json
----------------------------------------------------------------------
diff --git 
a/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/alerts.json 
b/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/alerts.json
index 5361bb5..efef2d0 100644
--- 
a/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/alerts.json
+++ 
b/ambari-server/src/main/resources/common-services/YARN/2.1.0.2.0/alerts.json
@@ -14,7 +14,9 @@
             "http": "{{mapred-site/mapreduce.jobhistory.webapp.address}}",
             "https": 
"{{mapred-site/mapreduce.jobhistory.webapp.https.address}}",
             "https_property": 
"{{mapred-site/mapreduce.jobhistory.http.policy}}",
-            "https_property_value": "HTTPS_ONLY"
+            "https_property_value": "HTTPS_ONLY",
+            "kerberos_keytab": 
"{{mapred-site/mapreduce.jobhistory.webapp.spnego-keytab-file}}",
+            "kerberos_principal": 
"{{mapred-site/mapreduce.jobhistory.webapp.spnego-principal}}"
           },
           "reporting": {
             "ok": {
@@ -24,7 +26,7 @@
               "text": "HTTP {0} response in {2:.3f} seconds"
             },
             "critical": {
-              "text": "Connection failed to {1}"
+              "text": "Connection failed to {1}: {3}"
             }
           }
         }
@@ -175,7 +177,9 @@
             "https": "{{yarn-site/yarn.nodemanager.webapp.https.address}}",
             "https_property": "{{yarn-site/yarn.http.policy}}",
             "https_property_value": "HTTPS_ONLY",
-            "default_port": 8042
+            "default_port": 8042,
+            "kerberos_keytab": 
"{{yarn-site/yarn.nodemanager.webapp.spnego-keytab-file}}",
+            "kerberos_principal": 
"{{yarn-site/yarn.nodemanager.webapp.spnego-principal}}"
           },
           "reporting": {
             "ok": {
@@ -185,7 +189,7 @@
               "text": "HTTP {0} response in {2:.3f} seconds"
             },
             "critical": {
-              "text": "Connection failed to {1}"
+              "text": "Connection failed to {1}: {3}"
             }
           }
         }
@@ -216,7 +220,9 @@
             "http": "{{yarn-site/yarn.resourcemanager.webapp.address}}",
             "https": "{{yarn-site/yarn.resourcemanager.webapp.https.address}}",
             "https_property": "{{yarn-site/yarn.http.policy}}",
-            "https_property_value": "HTTPS_ONLY"
+            "https_property_value": "HTTPS_ONLY",
+            "kerberos_keytab": 
"{{yarn-site/yarn.resourcemanager.webapp.spnego-keytab-file}}",
+            "kerberos_principal": 
"{{yarn-site/yarn.resourcemanager.webapp.spnego-principal}}"
           },
           "reporting": {
             "ok": {
@@ -226,7 +232,7 @@
               "text": "HTTP {0} response in {2:.3f} seconds"
             },
             "critical": {
-              "text": "Connection failed to {1}"
+              "text": "Connection failed to {1}: {3}"
             }
           }
         }
@@ -333,7 +339,9 @@
             "http": "{{yarn-site/yarn.timeline-service.webapp.address}}",
             "https": 
"{{yarn-site/yarn.timeline-service.webapp.https.address}}",
             "https_property": "{{yarn-site/yarn.http.policy}}",
-            "https_property_value": "HTTPS_ONLY"
+            "https_property_value": "HTTPS_ONLY",
+            "kerberos_keytab": 
"{{yarn-site/yarn.timeline-service.http-authentication.kerberos.keytab}}",
+            "kerberos_principal": 
"{{yarn-site/yarn.timeline-service.http-authentication.kerberos.principal}}"
           },
           "reporting": {
             "ok": {
@@ -343,7 +351,7 @@
               "text": "HTTP {0} response in {2:.3f} seconds"
             },
             "critical": {
-              "text": "Connection failed to {1}"
+              "text": "Connection failed to {1}: {3}"
             }
           }
         }

Reply via email to