AmbariConfig.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. #!/usr/bin/env python
  2. '''
  3. Licensed to the Apache Software Foundation (ASF) under one
  4. or more contributor license agreements. See the NOTICE file
  5. distributed with this work for additional information
  6. regarding copyright ownership. The ASF licenses this file
  7. to you under the Apache License, Version 2.0 (the
  8. "License"); you may not use this file except in compliance
  9. with the License. You may obtain a copy of the License at
  10. http://www.apache.org/licenses/LICENSE-2.0
  11. Unless required by applicable law or agreed to in writing, software
  12. distributed under the License is distributed on an "AS IS" BASIS,
  13. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. See the License for the specific language governing permissions and
  15. limitations under the License.
  16. '''
  17. import logging
  18. import ConfigParser
  19. import StringIO
  20. import hostname
  21. import ambari_simplejson as json
  22. import os
  23. from ambari_commons import OSConst
  24. from ambari_commons.os_family_impl import OsFamilyFuncImpl, OsFamilyImpl
  25. logger = logging.getLogger(__name__)
  26. content = """
  27. [server]
  28. hostname=localhost
  29. url_port=8440
  30. secured_url_port=8441
  31. [agent]
  32. prefix={ps}tmp{ps}ambari-agent
  33. tmp_dir={ps}tmp{ps}ambari-agent{ps}tmp
  34. data_cleanup_interval=86400
  35. data_cleanup_max_age=2592000
  36. data_cleanup_max_size_MB = 100
  37. ping_port=8670
  38. cache_dir={ps}var{ps}lib{ps}ambari-agent{ps}cache
  39. parallel_execution=0
  40. system_resource_overrides={ps}etc{ps}resource_overrides
  41. [services]
  42. [python]
  43. custom_actions_dir = {ps}var{ps}lib{ps}ambari-agent{ps}resources{ps}custom_actions
  44. [network]
  45. use_system_proxy_settings=true
  46. [security]
  47. keysdir={ps}tmp{ps}ambari-agent
  48. server_crt=ca.crt
  49. passphrase_env_var_name=AMBARI_PASSPHRASE
  50. [heartbeat]
  51. state_interval = 6
  52. dirs={ps}etc{ps}hadoop,{ps}etc{ps}hadoop{ps}conf,{ps}var{ps}run{ps}hadoop,{ps}var{ps}log{ps}hadoop
  53. log_lines_count=300
  54. iddle_interval_min=1
  55. iddle_interval_max=10
  56. [logging]
  57. log_command_executes = 0
  58. """.format(ps=os.sep)
  59. servicesToPidNames = {
  60. 'GLUSTERFS' : 'glusterd.pid$',
  61. 'NAMENODE': 'hadoop-{USER}-namenode.pid$',
  62. 'SECONDARY_NAMENODE': 'hadoop-{USER}-secondarynamenode.pid$',
  63. 'DATANODE': 'hadoop-{USER}-datanode.pid$',
  64. 'JOBTRACKER': 'hadoop-{USER}-jobtracker.pid$',
  65. 'TASKTRACKER': 'hadoop-{USER}-tasktracker.pid$',
  66. 'RESOURCEMANAGER': 'yarn-{USER}-resourcemanager.pid$',
  67. 'NODEMANAGER': 'yarn-{USER}-nodemanager.pid$',
  68. 'HISTORYSERVER': 'mapred-{USER}-historyserver.pid$',
  69. 'JOURNALNODE': 'hadoop-{USER}-journalnode.pid$',
  70. 'ZKFC': 'hadoop-{USER}-zkfc.pid$',
  71. 'OOZIE_SERVER': 'oozie.pid',
  72. 'ZOOKEEPER_SERVER': 'zookeeper_server.pid',
  73. 'FLUME_SERVER': 'flume-node.pid',
  74. 'TEMPLETON_SERVER': 'templeton.pid',
  75. 'HBASE_MASTER': 'hbase-{USER}-master.pid',
  76. 'HBASE_REGIONSERVER': 'hbase-{USER}-regionserver.pid',
  77. 'HCATALOG_SERVER': 'webhcat.pid',
  78. 'KERBEROS_SERVER': 'kadmind.pid',
  79. 'HIVE_SERVER': 'hive-server.pid',
  80. 'HIVE_METASTORE': 'hive.pid',
  81. 'HIVE_SERVER_INTERACTIVE' : 'hive-interactive.pid',
  82. 'MYSQL_SERVER': 'mysqld.pid',
  83. 'HUE_SERVER': '/var/run/hue/supervisor.pid',
  84. 'WEBHCAT_SERVER': 'webhcat.pid',
  85. }
  86. #Each service, which's pid depends on user should provide user mapping
  87. servicesToLinuxUser = {
  88. 'NAMENODE': 'hdfs_user',
  89. 'SECONDARY_NAMENODE': 'hdfs_user',
  90. 'DATANODE': 'hdfs_user',
  91. 'JOURNALNODE': 'hdfs_user',
  92. 'ZKFC': 'hdfs_user',
  93. 'JOBTRACKER': 'mapred_user',
  94. 'TASKTRACKER': 'mapred_user',
  95. 'RESOURCEMANAGER': 'yarn_user',
  96. 'NODEMANAGER': 'yarn_user',
  97. 'HISTORYSERVER': 'mapred_user',
  98. 'HBASE_MASTER': 'hbase_user',
  99. 'HBASE_REGIONSERVER': 'hbase_user',
  100. }
  101. pidPathVars = [
  102. {'var' : 'glusterfs_pid_dir_prefix',
  103. 'defaultValue' : '/var/run'},
  104. {'var' : 'hadoop_pid_dir_prefix',
  105. 'defaultValue' : '/var/run/hadoop'},
  106. {'var' : 'hadoop_pid_dir_prefix',
  107. 'defaultValue' : '/var/run/hadoop'},
  108. {'var' : 'hbase_pid_dir',
  109. 'defaultValue' : '/var/run/hbase'},
  110. {'var' : 'zk_pid_dir',
  111. 'defaultValue' : '/var/run/zookeeper'},
  112. {'var' : 'oozie_pid_dir',
  113. 'defaultValue' : '/var/run/oozie'},
  114. {'var' : 'hcat_pid_dir',
  115. 'defaultValue' : '/var/run/webhcat'},
  116. {'var' : 'hive_pid_dir',
  117. 'defaultValue' : '/var/run/hive'},
  118. {'var' : 'mysqld_pid_dir',
  119. 'defaultValue' : '/var/run/mysqld'},
  120. {'var' : 'hcat_pid_dir',
  121. 'defaultValue' : '/var/run/webhcat'},
  122. {'var' : 'yarn_pid_dir_prefix',
  123. 'defaultValue' : '/var/run/hadoop-yarn'},
  124. {'var' : 'mapred_pid_dir_prefix',
  125. 'defaultValue' : '/var/run/hadoop-mapreduce'},
  126. ]
  127. class AmbariConfig:
  128. TWO_WAY_SSL_PROPERTY = "security.server.two_way_ssl"
  129. AMBARI_PROPERTIES_CATEGORY = 'agentConfig'
  130. SERVER_CONNECTION_INFO = "{0}/connection_info"
  131. CONNECTION_PROTOCOL = "https"
  132. config = None
  133. net = None
  134. def __init__(self):
  135. global content
  136. self.config = ConfigParser.RawConfigParser()
  137. self.config.readfp(StringIO.StringIO(content))
  138. def get(self, section, value, default=None):
  139. try:
  140. return str(self.config.get(section, value)).strip()
  141. except ConfigParser.Error, err:
  142. if default != None:
  143. return default
  144. raise err
  145. def set(self, section, option, value):
  146. self.config.set(section, option, value)
  147. def add_section(self, section):
  148. self.config.add_section(section)
  149. def has_section(self, section):
  150. return self.config.has_section(section)
  151. def setConfig(self, customConfig):
  152. self.config = customConfig
  153. def getConfig(self):
  154. return self.config
  155. @classmethod
  156. def get_resolved_config(cls, home_dir=""):
  157. if hasattr(cls, "_conf_cache"):
  158. return getattr(cls, "_conf_cache")
  159. config = cls()
  160. configPath = os.path.abspath(cls.getConfigFile(home_dir))
  161. try:
  162. if os.path.exists(configPath):
  163. config.read(configPath)
  164. else:
  165. raise Exception("No config found at {0}, use default".format(configPath))
  166. except Exception, err:
  167. logger.warn(err)
  168. setattr(cls, "_conf_cache", config)
  169. return config
  170. @staticmethod
  171. @OsFamilyFuncImpl(OsFamilyImpl.DEFAULT)
  172. def getConfigFile(home_dir=""):
  173. """
  174. Get the configuration file path.
  175. :param home_dir: In production, will be "". When running multiple Agents per host, each agent will have a unique path.
  176. :return: Configuration file path.
  177. """
  178. if 'AMBARI_AGENT_CONF_DIR' in os.environ:
  179. return os.path.join(os.environ['AMBARI_AGENT_CONF_DIR'], "ambari-agent.ini")
  180. else:
  181. # home_dir may be an empty string
  182. return os.path.join(os.sep, home_dir, "etc", "ambari-agent", "conf", "ambari-agent.ini")
  183. # TODO AMBARI-18733, change usages of this function to provide the home_dir.
  184. @staticmethod
  185. def getLogFile(home_dir=""):
  186. """
  187. Get the log file path.
  188. :param home_dir: In production, will be "". When running multiple Agents per host, each agent will have a unique path.
  189. :return: Log file path.
  190. """
  191. if 'AMBARI_AGENT_LOG_DIR' in os.environ:
  192. return os.path.join(os.environ['AMBARI_AGENT_LOG_DIR'], "ambari-agent.log")
  193. else:
  194. return os.path.join(os.sep, home_dir, "var", "log", "ambari-agent", "ambari-agent.log")
  195. # TODO AMBARI-18733, change usages of this function to provide the home_dir.
  196. @staticmethod
  197. def getAlertsLogFile(home_dir=""):
  198. """
  199. Get the alerts log file path.
  200. :param home_dir: In production, will be "". When running multiple Agents per host, each agent will have a unique path.
  201. :return: Alerts log file path.
  202. """
  203. if 'AMBARI_AGENT_LOG_DIR' in os.environ:
  204. return os.path.join(os.environ['AMBARI_AGENT_LOG_DIR'], "ambari-agent.log")
  205. else:
  206. return os.path.join(os.sep, home_dir, "var", "log", "ambari-agent", "ambari-alerts.log")
  207. # TODO AMBARI-18733, change usages of this function to provide the home_dir.
  208. @staticmethod
  209. def getOutFile(home_dir=""):
  210. """
  211. Get the out file path.
  212. :param home_dir: In production, will be "". When running multiple Agents per host, each agent will have a unique path.
  213. :return: Out file path.
  214. """
  215. if 'AMBARI_AGENT_LOG_DIR' in os.environ:
  216. return os.path.join(os.environ['AMBARI_AGENT_LOG_DIR'], "ambari-agent.out")
  217. else:
  218. return os.path.join(os.sep, home_dir, "var", "log", "ambari-agent", "ambari-agent.out")
  219. def has_option(self, section, option):
  220. return self.config.has_option(section, option)
  221. def remove_option(self, section, option):
  222. return self.config.remove_option(section, option)
  223. def load(self, data):
  224. self.config = ConfigParser.RawConfigParser(data)
  225. def read(self, filename):
  226. self.config.read(filename)
  227. def getServerOption(self, url, name, default=None):
  228. from ambari_agent.NetUtil import NetUtil
  229. status, response = NetUtil(self).checkURL(url)
  230. if status is True:
  231. try:
  232. data = json.loads(response)
  233. if name in data:
  234. return data[name]
  235. except:
  236. pass
  237. return default
  238. def get_api_url(self, server_hostname):
  239. return "%s://%s:%s" % (self.CONNECTION_PROTOCOL,
  240. server_hostname,
  241. self.get('server', 'url_port'))
  242. def isTwoWaySSLConnection(self, server_hostname):
  243. req_url = self.get_api_url(server_hostname)
  244. response = self.getServerOption(self.SERVER_CONNECTION_INFO.format(req_url), self.TWO_WAY_SSL_PROPERTY, 'false')
  245. if response is None:
  246. return False
  247. elif response.lower() == "true":
  248. return True
  249. else:
  250. return False
  251. def get_parallel_exec_option(self):
  252. return int(self.get('agent', 'parallel_execution', 0))
  253. def use_system_proxy_setting(self):
  254. """
  255. Return `True` if Agent need to honor system proxy setting and `False` if not
  256. :rtype bool
  257. """
  258. return "true" == self.get("network", "use_system_proxy_settings", "true").lower()
  259. def get_multiprocess_status_commands_executor_enabled(self):
  260. return bool(int(self.get('agent', 'multiprocess_status_commands_executor_enabled', 1)))
  261. def update_configuration_from_registration(self, reg_resp):
  262. if reg_resp and AmbariConfig.AMBARI_PROPERTIES_CATEGORY in reg_resp:
  263. if not self.has_section(AmbariConfig.AMBARI_PROPERTIES_CATEGORY):
  264. self.add_section(AmbariConfig.AMBARI_PROPERTIES_CATEGORY)
  265. for k,v in reg_resp[AmbariConfig.AMBARI_PROPERTIES_CATEGORY].items():
  266. self.set(AmbariConfig.AMBARI_PROPERTIES_CATEGORY, k, v)
  267. logger.info("Updating config property (%s) with value (%s)", k, v)
  268. pass
  269. def get_force_https_protocol(self):
  270. return self.get('security', 'force_https_protocol', default="PROTOCOL_TLSv1")
  271. def isSameHostList(hostlist1, hostlist2):
  272. is_same = True
  273. if (hostlist1 is not None and hostlist2 is not None):
  274. if (len(hostlist1) != len(hostlist2)):
  275. is_same = False
  276. else:
  277. host_lookup = {}
  278. for item1 in hostlist1:
  279. host_lookup[item1.lower()] = True
  280. for item2 in hostlist2:
  281. if item2.lower() in host_lookup:
  282. del host_lookup[item2.lower()]
  283. else:
  284. is_same = False
  285. break
  286. pass
  287. elif (hostlist1 is not None or hostlist2 is not None):
  288. is_same = False
  289. return is_same
  290. def updateConfigServerHostname(configFile, new_hosts):
  291. # update agent config file
  292. agent_config = ConfigParser.ConfigParser()
  293. agent_config.read(configFile)
  294. server_hosts = agent_config.get('server', 'hostname')
  295. if new_hosts is not None:
  296. new_host_names = hostname.arrayFromCsvString(new_hosts)
  297. if not isSameHostList(server_hosts, new_host_names):
  298. print "Updating server hostname from " + server_hosts + " to " + new_hosts
  299. agent_config.set('server', 'hostname', new_hosts)
  300. with (open(configFile, "wb")) as new_agent_config:
  301. agent_config.write(new_agent_config)
  302. def main():
  303. print AmbariConfig().config
  304. if __name__ == "__main__":
  305. main()