Selaa lähdekoodia

AMBARI-10882 Allow NFS mounts to be skipped during agent health check (dsen)

Dmytro Sen 10 vuotta sitten
vanhempi
commit
44b6e7b979

+ 0 - 4
ambari-agent/conf/unix/ambari-agent.ini

@@ -31,10 +31,6 @@ tolerate_download_failures=true
 run_as_user=root
 parallel_execution=0
 
-[command]
-maxretries=2
-sleepBetweenRetries=1
-
 [security]
 keysdir=/var/lib/ambari-agent/keys
 server_crt=ca.crt

+ 0 - 4
ambari-agent/conf/windows/ambari-agent.ini

@@ -30,10 +30,6 @@ cache_dir=cache
 tolerate_download_failures=true
 parallel_execution=0
 
-[command]
-maxretries=2
-sleepBetweenRetries=1
-
 [security]
 keysdir=keys
 server_crt=ca.crt

+ 11 - 4
ambari-agent/src/main/python/ambari_agent/AmbariConfig.py

@@ -50,10 +50,6 @@ parallel_execution=0
 [python]
 custom_actions_dir = {ps}var{ps}lib{ps}ambari-agent{ps}resources{ps}custom_actions
 
-[command]
-maxretries=2
-sleepBetweenRetries=1
-
 [security]
 keysdir={ps}tmp{ps}ambari-agent
 server_crt=ca.crt
@@ -146,6 +142,7 @@ pidPathVars = [
 
 class AmbariConfig:
   TWO_WAY_SSL_PROPERTY = "security.server.two_way_ssl"
+  AMBARI_PROPERTIES_CATEGORY = 'agentConfig'
   SERVER_CONNECTION_INFO = "{0}/connection_info"
   CONNECTION_PROTOCOL = "https"
 
@@ -172,6 +169,9 @@ class AmbariConfig:
   def add_section(self, section):
     self.config.add_section(section)
 
+  def has_section(self, section):
+    return self.config.has_section(section)
+
   def setConfig(self, customConfig):
     self.config = customConfig
 
@@ -249,6 +249,13 @@ class AmbariConfig:
   def get_parallel_exec_option(self):
     return int(self.get('agent', 'parallel_execution', 0))
 
+  def update_configuration_from_registration(self, reg_resp):
+    if reg_resp and AmbariConfig.AMBARI_PROPERTIES_CATEGORY in reg_resp:
+      if not self.has_section(AmbariConfig.AMBARI_PROPERTIES_CATEGORY):
+        self.add_section(AmbariConfig.AMBARI_PROPERTIES_CATEGORY)
+      for k,v in reg_resp[AmbariConfig.AMBARI_PROPERTIES_CATEGORY].items():
+        self.set(AmbariConfig.AMBARI_PROPERTIES_CATEGORY, k, v)
+    pass
 
 def updateConfigServerHostname(configFile, new_host):
   # update agent config file

+ 2 - 3
ambari-agent/src/main/python/ambari_agent/Controller.py

@@ -19,10 +19,8 @@ limitations under the License.
 '''
 
 import logging
-import signal
 import json
 import sys
-import platform
 import os
 import socket
 import time
@@ -163,7 +161,8 @@ class Controller(threading.Thread):
         self.cluster_configuration.update_configurations_from_heartbeat(ret)
 
         self.recovery_manager.update_configuration_from_registration(ret)
-
+        self.config.update_configuration_from_registration(ret)
+        logger.debug("Updated config:" + str(self.config))
         # always update alert definitions on registration
         self.alert_scheduler_handler.update_definitions(ret)
       except ssl.SSLError:

+ 16 - 10
ambari-agent/src/main/python/ambari_agent/Hardware.py

@@ -21,24 +21,23 @@ limitations under the License.
 import os.path
 import logging
 import subprocess
-import platform
 from ambari_commons.constants import AMBARI_SUDO_BINARY
 from ambari_commons.shell import shellRunner
 from Facter import Facter
-from ambari_commons.os_check import OSConst, OSCheck
+from ambari_commons.os_check import OSConst
 from ambari_commons.os_family_impl import OsFamilyFuncImpl, OsFamilyImpl
+from AmbariConfig import AmbariConfig
 logger = logging.getLogger()
 
 class Hardware:
   SSH_KEY_PATTERN = 'ssh.*key'
-  WINDOWS_GET_DRIVES_CMD ="foreach ($drive in [System.IO.DriveInfo]::getdrives()){$available = $drive.TotalFreeSpace;$used = $drive.TotalSize-$drive.TotalFreeSpace;$percent = ($used*100)/$drive.TotalSize;$size = $drive.TotalSize;$type = $drive.DriveFormat;$mountpoint = $drive.RootDirectory.FullName;echo \"$available $used $percent% $size $type $mountpoint\"}"
+  WINDOWS_GET_DRIVES_CMD = "foreach ($drive in [System.IO.DriveInfo]::getdrives()){$available = $drive.TotalFreeSpace;$used = $drive.TotalSize-$drive.TotalFreeSpace;$percent = ($used*100)/$drive.TotalSize;$size = $drive.TotalSize;$type = $drive.DriveFormat;$mountpoint = $drive.RootDirectory.FullName;echo \"$available $used $percent% $size $type $mountpoint\"}"
+  CHECK_REMOTE_MOUNTS_KEY = 'agent.check.remote.mounts'
 
   def __init__(self):
     self.hardware = {}
-    osdisks = Hardware.osdisks()
-    self.hardware['mounts'] = osdisks
-    otherInfo = Facter().facterInfo()
-    self.hardware.update(otherInfo)
+    self.hardware['mounts'] = Hardware.osdisks()
+    self.hardware.update(Facter().facterInfo())
     pass
 
   @staticmethod
@@ -64,12 +63,19 @@ class Hardware:
 
   @staticmethod
   @OsFamilyFuncImpl(OsFamilyImpl.DEFAULT)
-  def osdisks():
+  def osdisks(config = None):
     """ Run df to find out the disks on the host. Only works on linux
     platforms. Note that this parser ignores any filesystems with spaces
     and any mounts with spaces. """
     mounts = []
-    df = subprocess.Popen(["df", "-kPT"], stdout=subprocess.PIPE)
+    command = ["df", "-kPT"]
+    if config and \
+        config.has_option(AmbariConfig.AMBARI_PROPERTIES_CATEGORY, Hardware.CHECK_REMOTE_MOUNTS_KEY) and \
+        config.get(AmbariConfig.AMBARI_PROPERTIES_CATEGORY, Hardware.CHECK_REMOTE_MOUNTS_KEY).lower() == "false":
+      #limit listing to local file systems
+      command.append("-l")
+
+    df = subprocess.Popen(command, stdout=subprocess.PIPE)
     dfdata = df.communicate()[0]
     lines = dfdata.splitlines()
     for l in lines:
@@ -89,7 +95,7 @@ class Hardware:
 
   @staticmethod
   @OsFamilyFuncImpl(OSConst.WINSRV_FAMILY)
-  def osdisks():
+  def osdisks(config = None):
     mounts = []
     runner = shellRunner()
     command_result = runner.runPowershell(script_block=Hardware.WINDOWS_GET_DRIVES_CMD)

+ 1 - 1
ambari-agent/src/main/python/ambari_agent/Heartbeat.py

@@ -87,7 +87,7 @@ class Heartbeat:
       # this must be the last step before returning heartbeat
       hostInfo.register(nodeInfo, componentsMapped, commandsInProgress)
       heartbeat['agentEnv'] = nodeInfo
-      mounts = Hardware.osdisks()
+      mounts = Hardware.osdisks(self.config)
       heartbeat['mounts'] = mounts
 
       if logger.isEnabledFor(logging.DEBUG):

+ 0 - 13
ambari-agent/src/main/python/ambari_agent/HostInfo.py

@@ -19,7 +19,6 @@ limitations under the License.
 '''
 
 import glob
-import hostname
 import logging
 import os
 import re
@@ -32,7 +31,6 @@ from ambari_commons import OSCheck, OSConst
 from ambari_commons.firewall import Firewall
 from ambari_commons.os_family_impl import OsFamilyImpl
 
-from ambari_agent.Hardware import Hardware
 from ambari_agent.HostCheckReportFileHandler import HostCheckReportFileHandler
 
 
@@ -163,23 +161,12 @@ class HostInfoLinux(HostInfo):
   def __init__(self, config=None):
     super(HostInfoLinux, self).__init__(config)
 
-  def osdiskAvailableSpace(self, path):
-    diskInfo = {}
-    try:
-      df = subprocess.Popen(["df", "-kPT", path], stdout=subprocess.PIPE)
-      dfdata = df.communicate()[0]
-      return Hardware.extractMountInfo(dfdata.splitlines()[-1])
-    except:
-      pass
-    return diskInfo
-
   def checkUsers(self, users, results):
     f = open('/etc/passwd', 'r')
     for userLine in f:
       fields = userLine.split(":")
       if fields[0] in users:
         result = {}
-        homeDir = fields[5]
         result['name'] = fields[0]
         result['homeDir'] = fields[5]
         result['status'] = "Available"

+ 2 - 2
ambari-agent/src/main/python/ambari_agent/RecoveryManager.py

@@ -416,7 +416,7 @@ class RecoveryManager:
   def update_configuration_from_registration(self, reg_resp):
     """
     TODO: Server sends the recovery configuration - call update_config after parsing
-    "recovery_config": {
+    "recoveryConfig": {
       "type" : "DEFAULT|AUTO_START|FULL",
       "maxCount" : 10,
       "windowInMinutes" : 60,
@@ -685,4 +685,4 @@ def main(argv=None):
 
 
 if __name__ == '__main__':
-  main()
+  main()

+ 27 - 0
ambari-agent/src/test/python/ambari_agent/TestHardware.py

@@ -26,6 +26,7 @@ import socket
 from only_for_platform import not_for_platform, PLATFORM_WINDOWS
 from ambari_agent import hostname
 from ambari_agent.Hardware import Hardware
+from ambari_agent.AmbariConfig import AmbariConfig
 from ambari_agent.Facter import Facter, FacterLinux
 from ambari_commons import OSCheck
 
@@ -64,6 +65,32 @@ class TestHardware(TestCase):
 
     self.assertTrue(len(result['mounts']) == len(osdisks))
 
+  @patch.object(OSCheck, "get_os_type")
+  @patch.object(OSCheck, "get_os_version")
+  @patch("subprocess.Popen")
+  @patch("subprocess.Popen.communicate")
+
+  # @patch.object(AmbariConfig, "get")
+  # @patch.object(AmbariConfig, "has_option")
+  def test_osdisks_remote(self, communicate_mock, popen_mock,
+                          get_os_version_mock, get_os_type_mock):
+    # has_option_mock.return_value = True
+    # get_mock.return_value = "true"
+    get_os_type_mock.return_value = "suse"
+    get_os_version_mock.return_value = "11"
+    Hardware.osdisks()
+    popen_mock.assert_called_with(["df","-kPT"], stdout=-1)
+    config = AmbariConfig()
+    Hardware.osdisks(config)
+    popen_mock.assert_called_with(["df","-kPT"], stdout=-1)
+    config.add_section(AmbariConfig.AMBARI_PROPERTIES_CATEGORY)
+    config.set(AmbariConfig.AMBARI_PROPERTIES_CATEGORY, Hardware.CHECK_REMOTE_MOUNTS_KEY, "true")
+    Hardware.osdisks(config)
+    popen_mock.assert_called_with(["df","-kPT"], stdout=-1)
+    config.set(AmbariConfig.AMBARI_PROPERTIES_CATEGORY, Hardware.CHECK_REMOTE_MOUNTS_KEY, "false")
+    Hardware.osdisks(config)
+    popen_mock.assert_called_with(["df","-kPT", "-l"], stdout=-1)
+
   def test_extractMountInfo(self):
     outputLine = "device type size used available percent mountpoint"
     result = Hardware.extractMountInfo(outputLine)

+ 0 - 17
ambari-agent/src/test/python/ambari_agent/TestHostInfo.py

@@ -405,23 +405,6 @@ class TestHostInfo(TestCase):
     self.assertTrue(list[0]['hadoop'])
     self.assertEquals(list[0]['user'], 'user')
 
-  @patch("subprocess.Popen")
-  @patch.object(Hardware, 'extractMountInfo')
-  def test_osdiskAvailableSpace(self, extract_mount_info_mock, subproc_popen_mock):
-    hostInfo = HostInfoLinux()
-    p = MagicMock()
-    p.communicate.return_value = ['some']
-    subproc_popen_mock.return_value = p
-    extract_mount_info_mock.return_value = {'info' : 'info'}
-    result = hostInfo.osdiskAvailableSpace('')
-
-    self.assertTrue(result['info'], 'info')
-
-    p.communicate.return_value = ''
-    result = hostInfo.osdiskAvailableSpace('')
-
-    self.assertEquals(result, {})
-
   @patch.object(OSCheck, "get_os_type")
   @patch("subprocess.Popen")
   def test_checkLiveServices(self, subproc_popen, get_os_type_method):

+ 1 - 4
ambari-agent/src/test/python/unitTests.py

@@ -19,11 +19,8 @@ limitations under the License.
 '''
 
 import unittest
-import doctest
-from os.path import dirname, split, isdir
-import logging.handlers
+from os.path import isdir
 import logging
-import platform
 from only_for_platform import get_platform, PLATFORM_WINDOWS
 #TODO Add an option to randomize the tests' execution
 #from random import shuffle

+ 4 - 0
ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java

@@ -967,6 +967,10 @@ public class HeartBeatHandler {
     List<AlertDefinitionCommand> alertDefinitionCommands = getRegistrationAlertDefinitionCommands(hostname);
     response.setAlertDefinitionCommands(alertDefinitionCommands);
 
+    response.setAgentConfig(config.getAgentConfigsMap());
+    if(response.getAgentConfig() != null) {
+      LOG.debug("Agent configuration map set to " + response.getAgentConfig());
+    }
     response.setRecoveryConfig(RecoveryConfig.getRecoveryConfig(config));
     if(response.getRecoveryConfig() != null) {
       LOG.debug("Recovery configuration set to " + response.getRecoveryConfig().toString());

+ 13 - 0
ambari-server/src/main/java/org/apache/ambari/server/agent/RegistrationResponse.java

@@ -20,6 +20,7 @@ package org.apache.ambari.server.agent;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
 import org.codehaus.jackson.annotate.JsonProperty;
 
@@ -61,6 +62,9 @@ public class RegistrationResponse {
   @JsonProperty("recoveryConfig")
   private RecoveryConfig recoveryConfig;
 
+  @JsonProperty("agentConfig")
+  private Map<String, String> agentConfig;
+
   @JsonProperty("statusCommands")
   private List<StatusCommand> statusCommands = null;
 
@@ -125,6 +129,14 @@ public class RegistrationResponse {
     this.recoveryConfig = recoveryConfig;
   }
 
+  public Map<String, String> getAgentConfig() {
+    return agentConfig;
+  }
+
+  public void setAgentConfig(Map<String, String> agentConfig) {
+    this.agentConfig = agentConfig;
+  }
+
   @Override
   public String toString() {
     StringBuilder buffer = new StringBuilder("RegistrationResponse{");
@@ -133,6 +145,7 @@ public class RegistrationResponse {
     buffer.append(", statusCommands=").append(statusCommands);
     buffer.append(", alertDefinitionCommands=").append(alertDefinitionCommands);
     buffer.append(", recoveryConfig=").append(recoveryConfig);
+    buffer.append(", agentConfig=").append(agentConfig);
     buffer.append('}');
     return buffer.toString();
   }

+ 17 - 0
ambari-server/src/main/java/org/apache/ambari/server/configuration/Configuration.java

@@ -116,6 +116,8 @@ public class Configuration {
   public static final String CLIENT_API_SSL_CRT_PASS_FILE_NAME_KEY = "client.api.ssl.cert_pass_file";
   public static final String CLIENT_API_SSL_CRT_PASS_KEY = "client.api.ssl.crt_pass";
   public static final String CLIENT_API_SSL_KEY_NAME_KEY = "client.api.ssl.key_name";
+  public static final String CHECK_REMOTE_MOUNTS_KEY = "agent.check.remote.mounts";
+  public static final String CHECK_REMOTE_MOUNTS_DEFAULT = "true";
   public static final String SERVER_DB_NAME_KEY = "server.jdbc.database_name";
   public static final String SERVER_DB_NAME_DEFAULT = "ambari";
   public static final String REQUEST_READ_TIMEOUT = "views.request.read.timeout.millis";
@@ -380,6 +382,7 @@ public class Configuration {
 
   private Properties properties;
   private Map<String, String> configsMap;
+  private Map<String, String> agentConfigsMap;
   private CredentialProvider credentialProvider = null;
   private volatile boolean credentialProviderInitialized = false;
   private Map<String, String> customDbProperties = null;
@@ -485,7 +488,12 @@ public class Configuration {
   public Configuration(Properties properties) {
     this.properties = properties;
 
+    agentConfigsMap = new HashMap<String, String>();
+    agentConfigsMap.put(CHECK_REMOTE_MOUNTS_KEY, properties.getProperty(
+      CHECK_REMOTE_MOUNTS_KEY, CHECK_REMOTE_MOUNTS_DEFAULT));
+
     configsMap = new HashMap<String, String>();
+    configsMap.putAll(agentConfigsMap);
     configsMap.put(AMBARI_PYTHON_WRAP_KEY, properties.getProperty(
         AMBARI_PYTHON_WRAP_KEY, AMBARI_PYTHON_WRAP_DEFAULT));
     configsMap.put(SRVR_TWO_WAY_SSL_KEY, properties.getProperty(
@@ -774,6 +782,15 @@ public class Configuration {
     return configsMap;
   }
 
+  /**
+   * Get the map with server config parameters related to agent configuration.
+   * Keys - public constants of this class
+   * @return the map with server config parameters related to agent configuration
+   */
+  public Map<String, String> getAgentConfigsMap() {
+    return agentConfigsMap;
+  }
+
   /**
    * Checks if CSRF protection enabled
    * @return true if CSRF protection filter should be enabled

+ 50 - 17
ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java

@@ -285,8 +285,10 @@ public class TestHeartbeatHandler {
     cr.setRoleCommand("START");
     cr.setClusterName(DummyCluster);
 
-    cr.setConfigurationTags(new HashMap<String, Map<String,String>>() {{
-      put("global", new HashMap<String,String>() {{ put("tag", "version1"); }});
+    cr.setConfigurationTags(new HashMap<String, Map<String, String>>() {{
+      put("global", new HashMap<String, String>() {{
+        put("tag", "version1");
+      }});
     }});
 
     reports.add(cr);
@@ -348,8 +350,10 @@ public class TestHeartbeatHandler {
     cr.setStdOut("");
     cr.setExitCode(215);
     cr.setClusterName(DummyCluster);
-    cr.setConfigurationTags(new HashMap<String, Map<String,String>>() {{
-      put("global", new HashMap<String,String>() {{ put("tag", "version1"); }});
+    cr.setConfigurationTags(new HashMap<String, Map<String, String>>() {{
+      put("global", new HashMap<String, String>() {{
+        put("tag", "version1");
+      }});
     }});
     reports.add(cr);
     hb.setReports(reports);
@@ -359,10 +363,10 @@ public class TestHeartbeatHandler {
 
     ActionManager am = getMockActionManager();
     expect(am.getTasks(anyObject(List.class))).andReturn(
-        new ArrayList<HostRoleCommand>() {{
-          add(command);
-          add(command);
-        }});
+      new ArrayList<HostRoleCommand>() {{
+        add(command);
+        add(command);
+      }});
     replay(am);
 
     HeartBeatHandler handler = getHeartBeatHandler(am, aq);
@@ -520,14 +524,14 @@ public class TestHeartbeatHandler {
     assertTrue(serviceComponentHost1.isRestartRequired());
 
     final HostRoleCommand command = hostRoleCommandFactory.create(DummyHostname1,
-            Role.DATANODE, null, null);
+      Role.DATANODE, null, null);
 
     ActionManager am = getMockActionManager();
     expect(am.getTasks(anyObject(List.class))).andReturn(
-            new ArrayList<HostRoleCommand>() {{
-              add(command);
-              add(command);
-            }});
+      new ArrayList<HostRoleCommand>() {{
+        add(command);
+        add(command);
+      }});
     replay(am);
 
     HeartBeatHandler handler = getHeartBeatHandler(am, aq);
@@ -599,10 +603,10 @@ public class TestHeartbeatHandler {
 
     ActionManager am = getMockActionManager();
     expect(am.getTasks(anyObject(List.class))).andReturn(
-            new ArrayList<HostRoleCommand>() {{
-              add(command);
-              add(command);
-            }});
+      new ArrayList<HostRoleCommand>() {{
+        add(command);
+        add(command);
+      }});
     replay(am);
 
     HeartBeatHandler handler = getHeartBeatHandler(am, aq);
@@ -872,6 +876,35 @@ public class TestHeartbeatHandler {
     assertEquals(rc.getWindowInMinutes(), "60");
   }
 
+  @Test
+  public void testRegistrationAgentConfig() throws AmbariException,
+      InvalidStateTransitionException {
+    ActionManager am = getMockActionManager();
+    replay(am);
+    Clusters fsm = clusters;
+    HeartBeatHandler handler = new HeartBeatHandler(fsm, new ActionQueue(), am,
+                                                    injector);
+    clusters.addHost(DummyHostname1);
+    Host hostObject = clusters.getHost(DummyHostname1);
+    hostObject.setIPv4("ipv4");
+    hostObject.setIPv6("ipv6");
+
+    Register reg = new Register();
+    HostInfo hi = new HostInfo();
+    hi.setHostName(DummyHostname1);
+    hi.setOS(DummyOsType);
+    reg.setHostname(DummyHostname1);
+    reg.setCurrentPingPort(DummyCurrentPingPort);
+    reg.setHardwareProfile(hi);
+    reg.setAgentVersion(metaInfo.getServerVersion());
+    reg.setPrefix(Configuration.PREFIX_DIR);
+    RegistrationResponse rr = handler.handleRegistration(reg);
+    Map<String, String> config = rr.getAgentConfig();
+    assertFalse(config.isEmpty());
+    assertTrue(config.containsKey(Configuration.CHECK_REMOTE_MOUNTS_KEY));
+    assertTrue("true".equals(config.get(Configuration.CHECK_REMOTE_MOUNTS_KEY)));
+  }
+
   @Test
   public void testRegistrationWithBadVersion() throws AmbariException,
       InvalidStateTransitionException {