ambari_server_main.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  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 getpass
  18. import os
  19. import stat
  20. import subprocess
  21. import tempfile
  22. import sys
  23. from ambari_commons.exceptions import FatalException
  24. from ambari_commons.logging_utils import get_debug_mode, print_warning_msg, print_info_msg, \
  25. set_debug_mode_from_options
  26. from ambari_commons.os_check import OSConst
  27. from ambari_commons.os_family_impl import OsFamilyFuncImpl, OsFamilyImpl
  28. from ambari_commons.os_utils import is_root
  29. from ambari_server.dbConfiguration import ensure_dbms_is_running, ensure_jdbc_driver_is_installed
  30. from ambari_server.serverConfiguration import configDefaults, find_jdk, get_ambari_classpath, get_ambari_properties, \
  31. get_conf_dir, get_is_persisted, get_is_secure, get_java_exe_path, get_original_master_key, read_ambari_user, \
  32. PID_NAME, SECURITY_KEY_ENV_VAR_NAME, SECURITY_MASTER_KEY_LOCATION, \
  33. SETUP_OR_UPGRADE_MSG, check_database_name_property, parse_properties_file
  34. from ambari_server.serverUtils import refresh_stack_hash
  35. from ambari_server.setupHttps import get_fqdn
  36. from ambari_server.setupSecurity import save_master_key
  37. from ambari_server.utils import check_reverse_lookup, save_pid, locate_file, looking_for_pid, wait_for_pid, \
  38. save_main_pid_ex, check_exitcode
  39. # debug settings
  40. SERVER_START_DEBUG = False
  41. SUSPEND_START_MODE = False
  42. # server commands
  43. ambari_provider_module_option = ""
  44. ambari_provider_module = os.environ.get('AMBARI_PROVIDER_MODULE')
  45. if ambari_provider_module is not None:
  46. ambari_provider_module_option = "-Dprovider.module.class=" + \
  47. ambari_provider_module + " "
  48. jvm_args = os.getenv('AMBARI_JVM_ARGS', '-Xms512m -Xmx2048m')
  49. SERVER_START_CMD = "{0} " \
  50. "-server -XX:NewRatio=3 " \
  51. "-XX:+UseConcMarkSweepGC " + \
  52. "-XX:-UseGCOverheadLimit -XX:CMSInitiatingOccupancyFraction=60 " + \
  53. "{1} {2} " \
  54. "-cp {3} "\
  55. "org.apache.ambari.server.controller.AmbariServer " \
  56. "> {4} 2>&1 || echo $? > {5} &"
  57. SERVER_START_CMD_DEBUG = "{0} " \
  58. "-server -XX:NewRatio=2 " \
  59. "-XX:+UseConcMarkSweepGC " + \
  60. "{1} {2} " \
  61. " -Xdebug -Xrunjdwp:transport=dt_socket,address=5005," \
  62. "server=y,suspend={6} " \
  63. "-cp {3} " + \
  64. "org.apache.ambari.server.controller.AmbariServer " \
  65. "> {4} 2>&1 || echo $? > {5} &"
  66. SERVER_START_CMD_WINDOWS = "{0} " \
  67. "-server -XX:NewRatio=3 " \
  68. "-XX:+UseConcMarkSweepGC " + \
  69. "-XX:-UseGCOverheadLimit -XX:CMSInitiatingOccupancyFraction=60 " \
  70. "{1} {2} " \
  71. "-cp {3} " \
  72. "org.apache.ambari.server.controller.AmbariServer"
  73. SERVER_START_CMD_DEBUG_WINDOWS = "{0} " \
  74. "-server -XX:NewRatio=2 " \
  75. "-XX:+UseConcMarkSweepGC " \
  76. "{1} {2} " \
  77. "-Xdebug -Xrunjdwp:transport=dt_socket,address=5005,server=y,suspend={4} " \
  78. "-cp {3} " \
  79. "org.apache.ambari.server.controller.AmbariServer"
  80. SERVER_INIT_TIMEOUT = 5
  81. SERVER_START_TIMEOUT = 10
  82. SERVER_PING_TIMEOUT_WINDOWS = 5
  83. SERVER_PING_ATTEMPTS_WINDOWS = 4
  84. SERVER_SEARCH_PATTERN = "org.apache.ambari.server.controller.AmbariServer"
  85. EXITCODE_NAME = "ambari-server.exitcode"
  86. AMBARI_SERVER_DIE_MSG = "Ambari Server java process died with exitcode {0}. Check {1} for more information."
  87. # linux open-file limit
  88. ULIMIT_OPEN_FILES_KEY = 'ulimit.open.files'
  89. ULIMIT_OPEN_FILES_DEFAULT = 10000
  90. @OsFamilyFuncImpl(OSConst.WINSRV_FAMILY)
  91. def ensure_can_start_under_current_user(ambari_user):
  92. #Ignore the requirement to run as root. In Windows, by default the child process inherits the security context
  93. # and the environment from the parent process.
  94. return ""
  95. @OsFamilyFuncImpl(OsFamilyImpl.DEFAULT)
  96. def ensure_can_start_under_current_user(ambari_user):
  97. current_user = getpass.getuser()
  98. if ambari_user is None:
  99. err = "Unable to detect a system user for Ambari Server.\n" + SETUP_OR_UPGRADE_MSG
  100. raise FatalException(1, err)
  101. if current_user != ambari_user and not is_root():
  102. err = "Unable to start Ambari Server as user {0}. Please either run \"ambari-server start\" " \
  103. "command as root, as sudo or as user \"{1}\"".format(current_user, ambari_user)
  104. raise FatalException(1, err)
  105. return current_user
  106. @OsFamilyFuncImpl(OSConst.WINSRV_FAMILY)
  107. def ensure_server_security_is_configured():
  108. pass
  109. @OsFamilyFuncImpl(OsFamilyImpl.DEFAULT)
  110. def ensure_server_security_is_configured():
  111. if not is_root():
  112. print "Unable to check firewall status when starting without root privileges."
  113. print "Please do not forget to disable or adjust firewall if needed"
  114. def get_ulimit_open_files(properties):
  115. open_files_val = properties[ULIMIT_OPEN_FILES_KEY]
  116. open_files = int(open_files_val) if (open_files_val and int(open_files_val) > 0) else ULIMIT_OPEN_FILES_DEFAULT
  117. return open_files
  118. @OsFamilyFuncImpl(OSConst.WINSRV_FAMILY)
  119. def generate_child_process_param_list(ambari_user, current_user, java_exe, class_path, debug_start, suspend_mode):
  120. conf_dir = class_path
  121. if class_path.find(' ') != -1:
  122. conf_dir = '"' + class_path + '"'
  123. command_base = SERVER_START_CMD_DEBUG_WINDOWS if debug_start else SERVER_START_CMD_WINDOWS
  124. command = command_base.format(
  125. java_exe,
  126. ambari_provider_module_option,
  127. jvm_args,
  128. conf_dir,
  129. suspend_mode)
  130. environ = os.environ.copy()
  131. return (command, environ)
  132. @OsFamilyFuncImpl(OsFamilyImpl.DEFAULT)
  133. def generate_child_process_param_list(ambari_user, current_user, java_exe, class_path, debug_start, suspend_mode):
  134. from ambari_commons.os_linux import ULIMIT_CMD
  135. properties = get_ambari_properties()
  136. isSecure = get_is_secure(properties)
  137. (isPersisted, masterKeyFile) = get_is_persisted(properties)
  138. environ = os.environ.copy()
  139. # Need to handle master key not persisted scenario
  140. if isSecure and not masterKeyFile:
  141. prompt = False
  142. masterKey = environ.get(SECURITY_KEY_ENV_VAR_NAME)
  143. if masterKey is not None and masterKey != "":
  144. pass
  145. else:
  146. keyLocation = environ.get(SECURITY_MASTER_KEY_LOCATION)
  147. if keyLocation is not None:
  148. try:
  149. # Verify master key can be read by the java process
  150. with open(keyLocation, 'r'):
  151. pass
  152. except IOError:
  153. print_warning_msg("Cannot read Master key from path specified in "
  154. "environemnt.")
  155. prompt = True
  156. else:
  157. # Key not provided in the environment
  158. prompt = True
  159. if prompt:
  160. import pwd
  161. masterKey = get_original_master_key(properties)
  162. tempDir = tempfile.gettempdir()
  163. tempFilePath = tempDir + os.sep + "masterkey"
  164. save_master_key(masterKey, tempFilePath, True)
  165. if ambari_user != current_user:
  166. uid = pwd.getpwnam(ambari_user).pw_uid
  167. gid = pwd.getpwnam(ambari_user).pw_gid
  168. os.chown(tempFilePath, uid, gid)
  169. else:
  170. os.chmod(tempFilePath, stat.S_IREAD | stat.S_IWRITE)
  171. if tempFilePath is not None:
  172. environ[SECURITY_MASTER_KEY_LOCATION] = tempFilePath
  173. command_base = SERVER_START_CMD_DEBUG if debug_start else SERVER_START_CMD
  174. ulimit_cmd = "%s %s" % (ULIMIT_CMD, str(get_ulimit_open_files(properties)))
  175. command = command_base.format(java_exe,
  176. ambari_provider_module_option,
  177. jvm_args,
  178. class_path,
  179. configDefaults.SERVER_OUT_FILE,
  180. os.path.join(configDefaults.PID_DIR, EXITCODE_NAME),
  181. suspend_mode)
  182. # required to start properly server instance
  183. os.chdir(configDefaults.ROOT_FS_PATH)
  184. #For properly daemonization server should be started using shell as parent
  185. param_list = [locate_file('sh', '/bin'), "-c"]
  186. if is_root() and ambari_user != "root":
  187. # To inherit exported environment variables (especially AMBARI_PASSPHRASE),
  188. # from subprocess, we have to skip --login option of su command. That's why
  189. # we change dir to / (otherwise subprocess can face with 'permission denied'
  190. # errors while trying to list current directory
  191. cmd = "{ulimit_cmd} ; {su} {ambari_user} -s {sh_shell} -c '{command}'".format(ulimit_cmd=ulimit_cmd,
  192. su=locate_file('su', '/bin'), ambari_user=ambari_user,
  193. sh_shell=locate_file('sh', '/bin'), command=command)
  194. else:
  195. cmd = "{ulimit_cmd} ; {command}".format(ulimit_cmd=ulimit_cmd, command=command)
  196. param_list.append(cmd)
  197. return (param_list, environ)
  198. @OsFamilyFuncImpl(OSConst.WINSRV_FAMILY)
  199. def wait_for_server_start(pidFile, scmStatus):
  200. # Wait for the HTTP port to be open
  201. iter_start = 0
  202. while iter_start < SERVER_PING_ATTEMPTS_WINDOWS and not get_fqdn(SERVER_PING_TIMEOUT_WINDOWS):
  203. if scmStatus is not None:
  204. scmStatus.reportStartPending()
  205. iter_start += 1
  206. @OsFamilyFuncImpl(OsFamilyImpl.DEFAULT)
  207. def wait_for_server_start(pidFile, scmStatus):
  208. #wait for server process for SERVER_START_TIMEOUT seconds
  209. sys.stdout.write('Waiting for server start...')
  210. sys.stdout.flush()
  211. pids = looking_for_pid(SERVER_SEARCH_PATTERN, SERVER_INIT_TIMEOUT)
  212. found_pids = wait_for_pid(pids, SERVER_START_TIMEOUT)
  213. sys.stdout.write('\n')
  214. sys.stdout.flush()
  215. if found_pids <= 0:
  216. exitcode = check_exitcode(os.path.join(configDefaults.PID_DIR, EXITCODE_NAME))
  217. raise FatalException(-1, AMBARI_SERVER_DIE_MSG.format(exitcode, configDefaults.SERVER_OUT_FILE))
  218. else:
  219. save_main_pid_ex(pids, pidFile, [locate_file('sh', '/bin'),
  220. locate_file('bash', '/bin'),
  221. locate_file('dash', '/bin')], True)
  222. def server_process_main(options, scmStatus=None):
  223. # debug mode, including stop Java process at startup
  224. try:
  225. set_debug_mode_from_options(options)
  226. except AttributeError:
  227. pass
  228. if not check_reverse_lookup():
  229. print_warning_msg("The hostname was not found in the reverse DNS lookup. "
  230. "This may result in incorrect behavior. "
  231. "Please check the DNS setup and fix the issue.")
  232. check_database_name_property()
  233. parse_properties_file(options)
  234. ambari_user = read_ambari_user()
  235. current_user = ensure_can_start_under_current_user(ambari_user)
  236. print_info_msg("Ambari Server is not running...")
  237. jdk_path = find_jdk()
  238. if jdk_path is None:
  239. err = "No JDK found, please run the \"ambari-server setup\" " \
  240. "command to install a JDK automatically or install any " \
  241. "JDK manually to " + configDefaults.JDK_INSTALL_DIR
  242. raise FatalException(1, err)
  243. properties = get_ambari_properties()
  244. # Preparations
  245. if is_root():
  246. print configDefaults.MESSAGE_SERVER_RUNNING_AS_ROOT
  247. ensure_jdbc_driver_is_installed(options, properties)
  248. ensure_dbms_is_running(options, properties, scmStatus)
  249. if scmStatus is not None:
  250. scmStatus.reportStartPending()
  251. refresh_stack_hash(properties)
  252. if scmStatus is not None:
  253. scmStatus.reportStartPending()
  254. ensure_server_security_is_configured()
  255. if scmStatus is not None:
  256. scmStatus.reportStartPending()
  257. java_exe = get_java_exe_path()
  258. class_path = get_conf_dir()
  259. class_path = os.path.abspath(class_path) + os.pathsep + get_ambari_classpath()
  260. debug_mode = get_debug_mode()
  261. debug_start = (debug_mode & 1) or SERVER_START_DEBUG
  262. suspend_start = (debug_mode & 2) or SUSPEND_START_MODE
  263. suspend_mode = 'y' if suspend_start else 'n'
  264. (param_list, environ) = generate_child_process_param_list(ambari_user, current_user,
  265. java_exe, class_path, debug_start, suspend_mode)
  266. if not os.path.exists(configDefaults.PID_DIR):
  267. os.makedirs(configDefaults.PID_DIR, 0755)
  268. print_info_msg("Running server: " + str(param_list))
  269. procJava = subprocess.Popen(param_list, env=environ)
  270. pidJava = procJava.pid
  271. if pidJava <= 0:
  272. procJava.terminate()
  273. exitcode = procJava.returncode
  274. exitfile = os.path.join(configDefaults.PID_DIR, EXITCODE_NAME)
  275. save_pid(exitcode, exitfile)
  276. if scmStatus is not None:
  277. scmStatus.reportStopPending()
  278. raise FatalException(-1, AMBARI_SERVER_DIE_MSG.format(exitcode, configDefaults.SERVER_OUT_FILE))
  279. else:
  280. pidfile = os.path.join(configDefaults.PID_DIR, PID_NAME)
  281. save_pid(pidJava, pidfile)
  282. print "Server PID at: "+pidfile
  283. print "Server out at: "+configDefaults.SERVER_OUT_FILE
  284. print "Server log at: "+configDefaults.SERVER_LOG_FILE
  285. wait_for_server_start(pidfile, scmStatus)
  286. if scmStatus is not None:
  287. scmStatus.reportStarted()
  288. return procJava