validate_configs.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  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. Ambari Agent
  17. """
  18. import os
  19. import grp
  20. import re
  21. from resource_management import Script
  22. import sys
  23. CONFIG_PARAM_PREFIX = 'component_configurations'
  24. CONFIG_PARAM_SEPARATOR = '/'
  25. MAX_SUBST = 40
  26. # Check if the specified in config properties directory exists and is empty
  27. # or can be created on the host
  28. PROPERTIES_TO_CHECK = {
  29. # HDFS
  30. "NAMENODE": {
  31. "hadoop-env": ["hdfs_log_dir_prefix", "hadoop_pid_dir_prefix"],
  32. "hdfs-site": ["dfs.namenode.name.dir"]
  33. },
  34. "DATANODE": {
  35. "hadoop-env": ["hdfs_log_dir_prefix", "hadoop_pid_dir_prefix", "dfs.domain.socket.path"],
  36. "hdfs-site": ["dfs.datanode.data.dir"]
  37. },
  38. "SECONDARY_NAMENODE": {
  39. "hadoop-env": ["hdfs_log_dir_prefix", "hadoop_pid_dir_prefix"],
  40. "hdfs-site": ["dfs.namenode.checkpoint.dir", "dfs.namenode.checkpoint.edits.dir"]
  41. },
  42. "JOURNALNODE": {
  43. "hadoop-env": ["hdfs_log_dir_prefix", "hadoop_pid_dir_prefix"],
  44. "hdfs-site": ["dfs.journalnode.edits.dir"]
  45. },
  46. #MAPREDUCE
  47. "JOBTRACKER": {
  48. "mapred-env": ["mapred_local_dir", "mapred_system_dir", "mapred_jobstatus_dir"],
  49. "mapred-site": ["mapred.local.dir", "mapred.healthChecker.script.path", "mapred.job.tracker.persist.jobstatus.dir"]
  50. },
  51. "TASKTRACKER": {
  52. "mapred-env": ["mapred_local_dir", "mapred_system_dir", "mapred_jobstatus_dir"],
  53. "mapred-site": ["mapred.local.dir", "mapred.healthChecker.script.path"]
  54. },
  55. "MAPREDUCE_CLIENT": {
  56. "mapred-env": ["mapred_local_dir", "mapred_system_dir", "mapred_jobstatus_dir"],
  57. "mapred-site": ["mapred.local.dir", "mapred.healthChecker.script.path"]
  58. },
  59. "HISTORYSERVER": {
  60. "mapred-env": ["mapred_local_dir", "mapred_system_dir", "mapred_jobstatus_dir"],
  61. "mapred-site": ["mapred.local.dir", "mapred.healthChecker.script.path"]
  62. },
  63. #MAPREDUCE2
  64. "MAPREDUCE2_CLIENT": {
  65. "mapred-env": ["mapred_log_dir_prefix", "mapred_pid_dir_prefix"],
  66. "mapred-site": ["mapreduce.jobhistory.done-dir", "mapreduce.jobhistory.intermediate-done-dir"]
  67. },
  68. #YARN
  69. "RESOURCEMANAGER": {
  70. "yarn-env": ["yarn_log_dir_prefix", "yarn_pid_dir_prefix", ]
  71. },
  72. "NODEMANAGER": {
  73. "yarn-env": ["yarn_log_dir_prefix", "yarn_pid_dir_prefix", ],
  74. "yarn-site": ["yarn.nodemanager.log-dirs", "yarn.nodemanager.local-dirs", "yarn.nodemanager.log-dirs", "yarn.nodemanager.remote-app-log-dir"]
  75. },
  76. "YARN_CLIENT": {
  77. "yarn-env": ["yarn_log_dir_prefix", "yarn_pid_dir_prefix", ]
  78. },
  79. #ZOOKEEPER
  80. "ZOOKEEPER_SERVER": {
  81. "zookeeper-env": ["zk_data_dir", "zk_log_dir", "zk_pid_dir"]
  82. },
  83. "ZOOKEEPER_CLIENT": {
  84. "zookeeper-env": ["zk_data_dir", "zk_log_dir", "zk_pid_dir"]
  85. },
  86. #FLUME
  87. "FLUME_HANDLER": {
  88. "flume-env": ["flume_conf_dir", "flume_log_dir"]
  89. },
  90. #GANGLIA
  91. "GANGLIA_MONITOR": {
  92. "ganglia-env": ["ganglia_conf_dir", "ganglia_runtime_dir"]
  93. },
  94. "GANGLIA_SERVER": {
  95. "ganglia-env": ["ganglia_conf_dir", "ganglia_runtime_dir", "rrdcached_base_dir"]
  96. },
  97. #HBASE
  98. "HBASE_MASTER": {
  99. "hbase-env": ["hbase_log_dir", "hbase_pid_dir"],
  100. "hbase-site": ["hbase.tmp.dir", "hbase.local.dir"]
  101. },
  102. "HBASE_REGIONSERVER": {
  103. "hbase-env": ["hbase_log_dir", "hbase_pid_dir"],
  104. "hbase-site": ["hbase.tmp.dir", "hbase.local.dir"]
  105. },
  106. "HBASE_CLIENT": {
  107. "hbase-env": ["hbase_log_dir", "hbase_pid_dir"],
  108. "hbase-site": ["hbase.tmp.dir", "hbase.local.dir"]
  109. },
  110. #HIVE
  111. "HIVE_METASTORE": {
  112. "hive-env": ["hive_dbroot", "hive_log_dir", "hive_pid_dir"]
  113. },
  114. "HIVE_SERVER": {
  115. "hive-env": ["hive_dbroot", "hive_log_dir", "hive_pid_dir"]
  116. },
  117. "MYSQL_SERVER": {
  118. "hive-env": ["hive_dbroot", "hive_log_dir", "hive_pid_dir"]
  119. },
  120. "HIVE_CLIENT": {
  121. "hive-env": ["hive_log_dir", "hive_pid_dir"]
  122. },
  123. "HCAT": {
  124. "hive-env": ["hcat_log_dir", "hcat_pid_dir"]
  125. },
  126. #OOZIE
  127. "OOZIE_SERVER": {
  128. "oozie-env": ["oozie_data_dir", "oozie_log_dir", "oozie_pid_dir"]
  129. },
  130. #PIG - no directories to check
  131. #SQOOP - no directories to check
  132. #WEBHCAT - no directories to check
  133. #FALCON - no directories to check
  134. "FALCON_CLIENT": {
  135. "falcon-env": ["falcon_log_dir", "falcon_pid_dir", "falcon_local_dir", "falcon.embeddedmq.data"]
  136. },
  137. "FALCON_SERVER": {
  138. "falcon-env": ["falcon_log_dir", "falcon_pid_dir", "falcon_local_dir", "falcon.embeddedmq.data"]
  139. }
  140. #STORM - no directories to check
  141. #TEZ - no directories to check
  142. }
  143. # Check if the usernames exists
  144. # - if they do - make sure they belong the correct group
  145. # - if not - check if new users can be created.
  146. USERS_TO_GROUP_MAPPING = {
  147. #HDFS
  148. "NAMENODE" : {
  149. "hadoop-env" : {
  150. "hdfs_user" : "user_group",
  151. "smokeuser" : "user_group",
  152. }
  153. },
  154. "DATANODE" : {
  155. "hadoop-env" : {
  156. "hdfs_user" : "user_group",
  157. "smokeuser" : "user_group",
  158. }
  159. },
  160. "SECONDARY_NAMENODE" : {
  161. "hadoop-env" : {
  162. "hdfs_user" : "user_group",
  163. "smokeuser" : "user_group",
  164. }
  165. },
  166. "JOURNALNODE" : {
  167. "hadoop-env" : {
  168. "hdfs_user" : "user_group",
  169. "smokeuser" : "user_group",
  170. }
  171. },
  172. "HDFS_CLIENT" : {
  173. "hadoop-env" : {
  174. "hdfs_user" : "user_group",
  175. "smokeuser" : "user_group",
  176. }
  177. },
  178. #MAPREDUCE
  179. "JOBTRACKER": {
  180. "mapred-env": {
  181. "mapred_user" : "mapred_user"
  182. }
  183. },
  184. "TASKTRACKER": {
  185. "mapred-env": {
  186. "mapred_user" : "mapred_user"
  187. }
  188. },
  189. "MAPREDUCE_CLIENT": {
  190. "mapred-env": {
  191. "mapred_user" : "mapred_user"
  192. }
  193. },
  194. "HISTORYSERVER": {
  195. "mapred-env": {
  196. "mapred_user" : "mapred_user"
  197. }
  198. },
  199. #MAPREDUCE2
  200. "MAPREDUCE2_CLIENT": {
  201. "mapred-env": {
  202. "mapred_user" : "mapred_user"
  203. }
  204. },
  205. #YARN
  206. "RESOURCEMANAGER": {
  207. "yarn-env": {
  208. "yarn_user": "yarn_user"
  209. }
  210. },
  211. "NODEMANAGER": {
  212. "yarn-env": {
  213. "yarn_user": "yarn_user"
  214. }
  215. },
  216. "YARN_CLIENT": {
  217. "yarn-env": {
  218. "yarn_user": "yarn_user"
  219. }
  220. },
  221. #ZOOKEEPER
  222. "ZOOKEEPER_SERVER": {
  223. "zookeeper-env": {
  224. "zk_user" : "zk_user"
  225. }
  226. },
  227. "ZOOKEEPER_CLIENT": {
  228. "zookeeper-env": {
  229. "zk_user" : "zk_user"
  230. }
  231. },
  232. #FLUME
  233. "FLUME_HANDLER": {
  234. "flume-env": {
  235. "flume_user": "flume_user"
  236. }
  237. },
  238. #GANGLIA
  239. "GANGLIA_MONITOR": {
  240. "ganglia-env": {
  241. "gmond_user" : "gmond_user"
  242. }
  243. },
  244. "GANGLIA_SERVER": {
  245. "ganglia-env": {
  246. "gmetad_user" : "gmetad_user"
  247. }
  248. },
  249. #HBASE
  250. "HBASE_MASTER": {
  251. "hbase-env": {
  252. "hbase_user": "hbase_user"
  253. }
  254. },
  255. "HBASE_REGIONSERVER": {
  256. "hbase-env": {
  257. "hbase_user": "hbase_user"
  258. }
  259. },
  260. "HBASE_CLIENT": {
  261. "hbase-env": {
  262. "hbase_user": "hbase_user"
  263. }
  264. },
  265. #HIVE
  266. "HIVE_METASTORE": {
  267. "hive-env": {
  268. "hive_user": "hive_user"
  269. }
  270. },
  271. "HIVE_SERVER": {
  272. "hive-env": {
  273. "hive_user": "hive_user"
  274. }
  275. },
  276. "MYSQL_SERVER": {
  277. "hive-env": {
  278. "hive_user": "hive_user"
  279. }
  280. },
  281. "HIVE_CLIENT": {
  282. "hive-env": {
  283. "hive_user": "hive_user"
  284. }
  285. },
  286. "HCAT": {
  287. "hive-env": {
  288. "hive_user": "hive_user"
  289. }
  290. },
  291. #OOZIE
  292. "OOZIE_SERVER": {
  293. "oozie-env": {
  294. "oozie_user": "oozie_user"
  295. }
  296. },
  297. #PIG - no users to check
  298. #SQOOP - no users to check
  299. #WEBHCAT - no users to check
  300. #FALCON
  301. "FALCON_CLIENT": {
  302. "falcon-env": {
  303. "falcon_user": "falcon_user"
  304. }
  305. },
  306. "FALCON_SERVER": {
  307. "falcon-env": {
  308. "falcon_user": "falcon_user"
  309. }
  310. },
  311. #STORM
  312. "NIMBUS": {
  313. "storm-env": {
  314. "storm_user": "storm_user"
  315. }
  316. },
  317. "STORM_REST_API": {
  318. "storm-env": {
  319. "storm_user": "storm_user"
  320. }
  321. },
  322. "SUPERVISOR": {
  323. "storm-env": {
  324. "storm_user": "storm_user"
  325. }
  326. },
  327. "STORM_UI_SERVER": {
  328. "storm-env": {
  329. "storm_user": "storm_user"
  330. }
  331. },
  332. "DRPC_SERVER": {
  333. "storm-env": {
  334. "storm_user": "storm_user"
  335. }
  336. },
  337. #TEZ
  338. "TEZ_CLIENT": {
  339. "tez-env": {
  340. "tez_user": "tez_user"
  341. }
  342. }
  343. }
  344. class ValidateConfigs(Script):
  345. def actionexecute(self, env):
  346. config = Script.get_config()
  347. params = config['commandParams']
  348. validation_passed = self.check_users(params) and self.check_directories(params)
  349. if validation_passed:
  350. print 'All configurations validated!'
  351. else:
  352. self.fail_with_error('Configurations validation failed!')
  353. def check_directories(self, params):
  354. validation_failed = False
  355. properties_to_check = self.flatten_dict(PROPERTIES_TO_CHECK)
  356. for property, value in params.items():
  357. if property in properties_to_check:
  358. if self.dir_exists_or_not_empty_or_cant_be_created(self.get_value(property, params)):
  359. validation_failed = True
  360. return not validation_failed
  361. def check_users(self, params):
  362. validation_passed = True
  363. for user, group in self.dict_to_list(USERS_TO_GROUP_MAPPING).items():
  364. if user in params and group in params:
  365. username = self.get_value(user, params)
  366. groupname = self.get_value(group, params)
  367. if not self.check_user_in_group(username, groupname):
  368. if os.geteuid() != 0:
  369. msg = 'Validation failed. ' + username + ' is not a member of ' \
  370. + groupname + ' group and ' + username + ' account can\'t ' \
  371. 'be created!\n'
  372. sys.stderr.write('Error: ' + msg)
  373. validation_passed = False
  374. return validation_passed
  375. def flatten_dict(self, dic, prefix=CONFIG_PARAM_PREFIX, separator=CONFIG_PARAM_SEPARATOR):
  376. result = []
  377. for key, val in dic.items():
  378. sum_key = prefix + separator + key
  379. if isinstance(val, dict):
  380. result += self.flatten_dict(val, sum_key, separator)
  381. else:
  382. for v in val:
  383. result.append(sum_key + separator + v)
  384. return result
  385. def dir_exists_or_not_empty_or_cant_be_created(self, filepath):
  386. if os.path.isdir(filepath) and os.access(filepath, os.W_OK) and os.listdir(filepath):
  387. msg = 'Validation failed. Directory ' + filepath \
  388. + ' already exists and isn\'t empty!\n'
  389. sys.stderr.write('Error: ' + msg)
  390. return True
  391. elif not os.access(self.get_existed_subdir(filepath), os.W_OK):
  392. msg = 'Validation failed. Directory ' + filepath + ' can\'t be created!\n'
  393. sys.stderr.write('Error: ' + msg)
  394. return True
  395. return False
  396. def get_existed_subdir(self, path):
  397. if os.path.exists(path) and os.path.isdir(path):
  398. return path
  399. else:
  400. return self.get_existed_subdir(os.path.dirname(path))
  401. def dict_to_list(self, dic, prefix=CONFIG_PARAM_PREFIX, separator=CONFIG_PARAM_SEPARATOR):
  402. result = {}
  403. for key, val in dic.items():
  404. sum_key = prefix + separator + key
  405. if isinstance(val, dict):
  406. result.update(self.dict_to_list(val, sum_key, separator))
  407. else:
  408. result[sum_key] = prefix + separator + val
  409. return result
  410. # username is a member of groupname or new account can be created
  411. def check_user_in_group(self, username, groupname):
  412. try:
  413. result = username == groupname or username in grp.getgrnam(groupname).gr_mem
  414. except KeyError:
  415. result = False
  416. return result
  417. # handle values like $(some.another.property.name}
  418. def get_value(self, key, params):
  419. result = params[key]
  420. pattern = re.compile("\$\{[^\}\$\x0020]+\}")
  421. for depth in range(0, MAX_SUBST - 1):
  422. match = pattern.search(result)
  423. if match:
  424. start = match.start()
  425. end = match.end()
  426. rx = re.compile(r'(.*/)(.+)')
  427. name = rx.sub(r'\g<1>' + result[start + 2 : end - 1], key)
  428. try:
  429. value = params[name]
  430. except KeyError:
  431. return result
  432. result = result[:start] + value + result[end:]
  433. else:
  434. break
  435. return result
  436. if __name__ == "__main__":
  437. ValidateConfigs().execute()