ambari-server-windows.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  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 optparse
  18. from ambari_commons.ambari_service import AmbariService, ENV_PYTHON_PATH
  19. from ambari_commons.logging_utils import *
  20. from ambari_commons.os_utils import remove_file
  21. from ambari_commons.os_windows import SvcStatusCallback
  22. from ambari_server import utils
  23. from ambari_server.dbConfiguration import DBMSConfig
  24. from ambari_server.resourceFilesKeeper import ResourceFilesKeeper, KeeperException
  25. from ambari_server.serverConfiguration import *
  26. from ambari_server.serverSetup import setup, reset, is_server_running, upgrade
  27. from ambari_server.setupActions import *
  28. from ambari_server.setupSecurity import *
  29. from ambari_server.serverSetup_windows import SERVICE_PASSWORD_KEY, SERVICE_USERNAME_KEY
  30. # debug settings
  31. SERVER_START_DEBUG = False
  32. SUSPEND_START_MODE = False
  33. # server commands
  34. ambari_provider_module_option = ""
  35. ambari_provider_module = os.environ.get('AMBARI_PROVIDER_MODULE')
  36. #Common setup or upgrade message
  37. SETUP_OR_UPGRADE_MSG = "- If this is a new setup, then run the \"ambari-server setup\" command to create the user\n" \
  38. "- If this is an upgrade of an existing setup, run the \"ambari-server upgrade\" command.\n" \
  39. "Refer to the Ambari documentation for more information on setup and upgrade."
  40. AMBARI_SERVER_DIE_MSG = "Ambari Server java process died with exitcode {0}. Check {1} for more information."
  41. if ambari_provider_module is not None:
  42. ambari_provider_module_option = "-Dprovider.module.class=" +\
  43. ambari_provider_module + " "
  44. SERVER_START_CMD = \
  45. "-server -XX:NewRatio=3 "\
  46. "-XX:+UseConcMarkSweepGC " +\
  47. "-XX:-UseGCOverheadLimit -XX:CMSInitiatingOccupancyFraction=60 " +\
  48. ambari_provider_module_option +\
  49. os.getenv('AMBARI_JVM_ARGS', '-Xms512m -Xmx2048m') +\
  50. " -cp {0}" +\
  51. " org.apache.ambari.server.controller.AmbariServer"
  52. SERVER_START_CMD_DEBUG = \
  53. "-server -XX:NewRatio=2 -XX:+UseConcMarkSweepGC " +\
  54. ambari_provider_module_option +\
  55. os.getenv('AMBARI_JVM_ARGS', '-Xms512m -Xmx2048m') +\
  56. " -Xdebug -Xrunjdwp:transport=dt_socket,address=5005,"\
  57. "server=y,suspend={1} -cp {0}" +\
  58. " org.apache.ambari.server.controller.AmbariServer"
  59. SERVER_SEARCH_PATTERN = "org.apache.ambari.server.controller.AmbariServer"
  60. SERVER_INIT_TIMEOUT = 5
  61. SERVER_START_TIMEOUT = 10
  62. PID_NAME = "ambari-server.pid"
  63. EXITCODE_NAME = "ambari-server.exitcode"
  64. SERVER_VERSION_FILE_PATH = "server.version.file"
  65. # linux open-file limit
  66. ULIMIT_OPEN_FILES_KEY = 'ulimit.open.files'
  67. ULIMIT_OPEN_FILES_DEFAULT = 10000
  68. class AmbariServerService(AmbariService):
  69. AmbariService._svc_name_ = "Ambari Server"
  70. AmbariService._svc_display_name_ = "Ambari Server"
  71. AmbariService._svc_description_ = "Ambari Server"
  72. AmbariService._AdjustServiceVersion()
  73. # Adds the necessary script dir to the Python's modules path
  74. def _adjustPythonPath(self, current_dir):
  75. python_path = os.path.join(current_dir, "sbin")
  76. sys.path.insert(0, python_path)
  77. def SvcDoRun(self):
  78. scmStatus = SvcStatusCallback(self)
  79. properties = get_ambari_properties()
  80. self.options.verbose = get_value_from_properties(properties, VERBOSE_OUTPUT_KEY, self.options.verbose)
  81. self.options.debug = get_value_from_properties(properties, DEBUG_MODE_KEY, self.options.debug)
  82. self.options.suspend_start = get_value_from_properties(properties, SUSPEND_START_MODE_KEY, self.options.suspend_start)
  83. self.redirect_output_streams()
  84. childProc = server_process_main(self.options, scmStatus)
  85. if not self._StopOrWaitForChildProcessToFinish(childProc):
  86. return
  87. pid_file_path = PID_DIR + os.sep + PID_NAME
  88. remove_file(pid_file_path)
  89. pass
  90. def _InitOptionsParser(self):
  91. return init_options_parser()
  92. def redirect_output_streams(self):
  93. properties = get_ambari_properties()
  94. outFilePath = properties[SERVER_OUT_FILE_KEY]
  95. if (outFilePath is None or outFilePath == ""):
  96. outFilePath = SERVER_OUT_FILE
  97. self._RedirectOutputStreamsToFile(outFilePath)
  98. pass
  99. def ctrlHandler(ctrlType):
  100. AmbariServerService.DefCtrlCHandler()
  101. return True
  102. def svcsetup():
  103. AmbariServerService.set_ctrl_c_handler(ctrlHandler)
  104. # we don't save password between 'setup' runs, so we can't run Install every time. We run 'setup' only if user and
  105. # password provided or if service not installed
  106. if (SERVICE_USERNAME_KEY in os.environ and SERVICE_PASSWORD_KEY in os.environ):
  107. AmbariServerService.Install(username=os.environ[SERVICE_USERNAME_KEY], password=os.environ[SERVICE_PASSWORD_KEY])
  108. elif AmbariServerService.QueryStatus() == "not installed":
  109. AmbariServerService.Install()
  110. pass
  111. #
  112. # Starts the Ambari Server as a standalone process.
  113. # args:
  114. # <no arguments> = start the server as a process. For now, there is no restrictions for the number of server instances
  115. # that can run like this.
  116. # -s, --single-instance = Reserved for future use. When starting the server as a process, ensure only one instance of the process is running.
  117. # If this is the second instance of the process, the function fails.
  118. #
  119. def start(options):
  120. AmbariServerService.set_ctrl_c_handler(ctrlHandler)
  121. #Run as a normal process. Invoke the ServiceMain directly.
  122. childProc = server_process_main(options)
  123. childProc.wait()
  124. pid_file_path = PID_DIR + os.sep + PID_NAME
  125. remove_file(pid_file_path)
  126. #
  127. # Starts the Ambari Server as a service.
  128. # Start the server in normal mode, as a Windows service. If the Ambari server is
  129. # not registered as a service, the function fails. By default, only one instance of the service can
  130. # possibly run.
  131. #
  132. def svcstart():
  133. AmbariServerService.Start()
  134. pass
  135. def server_process_main(options, scmStatus=None):
  136. # set verbose
  137. try:
  138. global VERBOSE
  139. VERBOSE = options.verbose
  140. except AttributeError:
  141. pass
  142. # set silent
  143. try:
  144. global SILENT
  145. SILENT = options.silent
  146. except AttributeError:
  147. pass
  148. # debug mode
  149. try:
  150. global DEBUG_MODE
  151. DEBUG_MODE = options.debug
  152. except AttributeError:
  153. pass
  154. # stop Java process at startup?
  155. try:
  156. global SUSPEND_START_MODE
  157. SUSPEND_START_MODE = options.suspend_start
  158. except AttributeError:
  159. pass
  160. if not utils.check_reverse_lookup():
  161. print_warning_msg("The hostname was not found in the reverse DNS lookup. "
  162. "This may result in incorrect behavior. "
  163. "Please check the DNS setup and fix the issue.")
  164. properties = get_ambari_properties()
  165. print_info_msg("Ambari Server is not running...")
  166. conf_dir = get_conf_dir()
  167. jdk_path = find_jdk()
  168. if jdk_path is None:
  169. err = "No JDK found, please run the \"ambari-server setup\" " \
  170. "command to install a JDK automatically or install any " \
  171. "JDK manually to " + JDK_INSTALL_DIR
  172. raise FatalException(1, err)
  173. # Preparations
  174. result = ensure_dbms_is_running(options, properties, scmStatus)
  175. if result == -1:
  176. raise FatalException(-1, "Unable to connect to the database")
  177. if scmStatus is not None:
  178. scmStatus.reportStartPending()
  179. ensure_resources_are_organized(properties)
  180. if scmStatus is not None:
  181. scmStatus.reportStartPending()
  182. environ = os.environ.copy()
  183. ensure_server_security_is_configured(properties, environ)
  184. if scmStatus is not None:
  185. scmStatus.reportStartPending()
  186. conf_dir = os.path.abspath(conf_dir) + os.pathsep + get_ambari_classpath()
  187. if conf_dir.find(' ') != -1:
  188. conf_dir = '"' + conf_dir + '"'
  189. java_exe = jdk_path + os.sep + JAVA_EXE_SUBPATH
  190. pidfile = PID_DIR + os.sep + PID_NAME
  191. command_base = SERVER_START_CMD_DEBUG if (DEBUG_MODE or SERVER_START_DEBUG) else SERVER_START_CMD
  192. suspend_mode = 'y' if SUSPEND_START_MODE else 'n'
  193. command = command_base.format(conf_dir, suspend_mode)
  194. if not os.path.exists(PID_DIR):
  195. os.makedirs(PID_DIR, 0755)
  196. set_open_files_limit(get_ulimit_open_files());
  197. #Ignore the requirement to run as root. In Windows, by default the child process inherits the security context
  198. # and the environment from the parent process.
  199. param_list = java_exe + " " + command
  200. print_info_msg("Running server: " + str(param_list))
  201. procJava = subprocess.Popen(param_list, env=environ)
  202. #wait for server process for SERVER_START_TIMEOUT seconds
  203. print "Waiting for server start..."
  204. pidJava = procJava.pid
  205. if pidJava <= 0:
  206. procJava.terminate()
  207. exitcode = procJava.returncode
  208. exitfile = os.path.join(PID_DIR, EXITCODE_NAME)
  209. utils.save_pid(exitcode, exitfile)
  210. if scmStatus is not None:
  211. scmStatus.reportStopPending()
  212. raise FatalException(-1, AMBARI_SERVER_DIE_MSG.format(exitcode, SERVER_OUT_FILE))
  213. else:
  214. utils.save_pid(pidJava, pidfile)
  215. print "Server PID at: "+pidfile
  216. print "Server out at: "+SERVER_OUT_FILE
  217. print "Server log at: "+SERVER_LOG_FILE
  218. if scmStatus is not None:
  219. scmStatus.reportStarted()
  220. return procJava
  221. #Check the JDBC driver status
  222. #If not found abort
  223. #Get SQL Server service status from SCM
  224. #If 'stopped' then start it
  225. #Wait until the status is 'started' or a configured timeout elapses
  226. #If the timeout has been reached, bail out with exception
  227. def ensure_dbms_is_running(options, properties, scmStatus):
  228. dbms = DBMSConfig.create(options, properties, "Ambari")
  229. if not dbms._is_jdbc_driver_installed(properties):
  230. raise FatalException(-1, "JDBC driver is not installed. Run ambari-server setup and try again.")
  231. dbms.ensure_dbms_is_running(options, properties, scmStatus)
  232. dbms2 = DBMSConfig.create(options, properties, "Metrics")
  233. if dbms2.database_host.lower() != dbms.database_host.lower():
  234. dbms2.ensure_dbms_is_running(options, properties, scmStatus)
  235. pass
  236. def ensure_resources_are_organized(properties):
  237. resources_location = get_resources_location(properties)
  238. resource_files_keeper = ResourceFilesKeeper(resources_location)
  239. try:
  240. print "Organizing resource files at {0}...".format(resources_location,
  241. verbose=VERBOSE)
  242. resource_files_keeper.perform_housekeeping()
  243. except KeeperException, ex:
  244. msg = "Can not organize resource files at {0}: {1}".format(
  245. resources_location, str(ex))
  246. raise FatalException(-1, msg)
  247. def ensure_server_security_is_configured(properties, environ):
  248. pass
  249. #
  250. # Stops the Ambari Server.
  251. #
  252. def svcstop():
  253. AmbariServerService.Stop()
  254. ### Stack upgrade ###
  255. #def upgrade_stack(args, stack_id, repo_url=None, repo_url_os=None):
  256. def get_resources_location(properties):
  257. res_location = properties[RESOURCES_DIR_PROPERTY]
  258. if res_location is None:
  259. res_location = RESOURCES_DIR_DEFAULT
  260. return res_location
  261. # pass
  262. def get_stack_location(properties):
  263. stack_location = properties[STACK_LOCATION_KEY]
  264. if stack_location is None:
  265. stack_location = STACK_LOCATION_DEFAULT
  266. return stack_location
  267. # pass
  268. #
  269. # The Ambari Server status.
  270. #
  271. def svcstatus(options):
  272. options.exit_message = None
  273. statusStr = AmbariServerService.QueryStatus()
  274. print "Ambari Server is " + statusStr
  275. def get_ulimit_open_files():
  276. properties = get_ambari_properties()
  277. if properties == -1:
  278. print "Error reading ambari properties"
  279. return None
  280. open_files = int(properties[ULIMIT_OPEN_FILES_KEY])
  281. if open_files > 0:
  282. return open_files
  283. else:
  284. return ULIMIT_OPEN_FILES_DEFAULT
  285. def init_options_parser():
  286. parser = optparse.OptionParser(usage="usage: %prog action [options] [stack_id os]", )
  287. #parser.add_option('-i', '--create-db-script-file', dest="create_db_script_file",
  288. # default="resources" + os.sep + "Ambari-DDL-SQLServer-CREATELOCAL.sql",
  289. # help="File with database creation script")
  290. parser.add_option('-f', '--init-script-file', dest="init_db_script_file",
  291. default="resources" + os.sep + "Ambari-DDL-SQLServer-CREATE.sql",
  292. help="File with database setup script")
  293. parser.add_option('-r', '--drop-script-file', dest="cleanup_db_script_file",
  294. default="resources" + os.sep + "Ambari-DDL-SQLServer-DROP.sql",
  295. help="File with database cleanup script")
  296. parser.add_option('-j', '--java-home', dest="java_home", default=None,
  297. help="Use specified java_home. Must be valid on all hosts")
  298. parser.add_option("-v", "--verbose",
  299. action="store_true", dest="verbose", default=False,
  300. help="Print verbose status messages")
  301. parser.add_option("-s", "--silent",
  302. action="store_true", dest="silent", default=False,
  303. help="Silently accepts default prompt values")
  304. parser.add_option('-g', '--debug', action="store_true", dest='debug', default=False,
  305. help="Start ambari-server in debug mode")
  306. parser.add_option('-y', '--suspend-start', action="store_true", dest='suspend_start', default=False,
  307. help="Freeze ambari-server Java process at startup in debug mode")
  308. parser.add_option('-a', '--databasehost', dest="database_host", default=None,
  309. help="Hostname of database server")
  310. parser.add_option('-n', '--databaseport', dest="database_port", default=None,
  311. help="Database server listening port")
  312. parser.add_option('-d', '--databasename', dest="database_name", default=None,
  313. help="Database/Schema/Service name or ServiceID")
  314. parser.add_option('-w', '--windowsauth', action="store_true", dest="database_windows_auth", default=None,
  315. help="Integrated Windows authentication")
  316. parser.add_option('-u', '--databaseusername', dest="database_username", default=None,
  317. help="Database user login")
  318. parser.add_option('-p', '--databasepassword', dest="database_password", default=None,
  319. help="Database user password")
  320. parser.add_option('-t', '--init-metrics-script-file', dest="init_metrics_db_script_file", default=None,
  321. help="File with metrics database setup script")
  322. parser.add_option('-c', '--drop-metrics-script-file', dest="cleanup_metrics_db_script_file", default=None,
  323. help="File with metrics database cleanup script")
  324. parser.add_option('-m', '--metricsdatabasehost', dest="metrics_database_host", default=None,
  325. help="Hostname of metrics database server")
  326. parser.add_option('-o', '--metricsdatabaseport', dest="metrics_database_port", default=None,
  327. help="Metrics database server listening port")
  328. parser.add_option('-e', '--metricsdatabasename', dest="metrics_database_name", default=None,
  329. help="Metrics database/Schema/Service name or ServiceID")
  330. parser.add_option('-z', '--metricswindowsauth', action="store_true", dest="metrics_database_windows_auth", default=None,
  331. help="Integrated Windows authentication for the metrics database")
  332. parser.add_option('-q', '--metricsdatabaseusername', dest="metrics_database_username", default=None,
  333. help="Metrics database user login")
  334. parser.add_option('-l', '--metricsdatabasepassword', dest="metrics_database_password", default=None,
  335. help="Metrics database user password")
  336. parser.add_option('--jdbc-driver', default=None, dest="jdbc_driver",
  337. help="Specifies the path to the JDBC driver JAR file for the " \
  338. "database type specified with the --jdbc-db option. Used only with --jdbc-db option.")
  339. # -b, -i, -k and -x the remaining available short options
  340. # -h reserved for help
  341. return parser
  342. def are_cmd_line_db_args_blank(options):
  343. if (options.database_host is None \
  344. and options.database_name is None \
  345. and options.database_windows_auth is None \
  346. and options.database_username is None \
  347. and options.database_password is None \
  348. and options.metrics_database_host is None \
  349. and options.metrics_database_name is None \
  350. and options.metrics_database_windows_auth is None \
  351. and options.metrics_database_username is None \
  352. and options.metrics_database_password is None):
  353. return True
  354. return False
  355. def are_db_auth_options_ok(db_windows_auth, db_username, db_password):
  356. if db_windows_auth is True:
  357. return True
  358. else:
  359. if db_username is not None and db_username is not "" and db_password is not None and db_password is not "":
  360. return True
  361. return False
  362. def are_cmd_line_db_args_valid(options):
  363. if (options.database_host is not None and options.database_host is not "" \
  364. #and options.database_name is not None \ # ambari by default is ok
  365. and are_db_auth_options_ok(options.database_windows_auth,
  366. options.database_username,
  367. options.database_password) \
  368. and options.metrics_database_host is not None and options.metrics_database_host is not "" \
  369. #and options.metrics_database_name is not None \ # HadoopMetrics by default is ok
  370. and are_db_auth_options_ok(options.metrics_database_windows_auth,
  371. options.metrics_database_username,
  372. options.metrics_database_password)):
  373. return True
  374. return False
  375. def setup_security(args):
  376. need_restart = True
  377. #Print menu options
  378. print '=' * 75
  379. print 'Choose one of the following options: '
  380. print ' [1] Enable HTTPS for Ambari server.'
  381. print ' [2] Encrypt passwords stored in ambari.properties file.'
  382. print ' [3] Setup Ambari kerberos JAAS configuration.'
  383. print '=' * 75
  384. choice = get_validated_string_input('Enter choice, (1-3): ', '0', '[1-3]',
  385. 'Invalid choice', False, False)
  386. if choice == '1':
  387. need_restart = setup_https(args)
  388. elif choice == '2':
  389. setup_master_key()
  390. elif choice == '3':
  391. setup_ambari_krb5_jaas()
  392. else:
  393. raise FatalException('Unknown option for setup-security command.')
  394. return need_restart
  395. #
  396. # Main.
  397. #
  398. def main():
  399. parser = init_options_parser()
  400. (options, args) = parser.parse_args()
  401. #perform checks
  402. options.warnings = []
  403. options.must_set_database_options = False
  404. if are_cmd_line_db_args_blank(options):
  405. options.must_set_database_options = True
  406. #TODO Silent is invalid here, right?
  407. elif not are_cmd_line_db_args_valid(options):
  408. parser.error('All database options should be set. Please see help for the options.')
  409. ## jdbc driver and db options validation
  410. #if options.jdbc_driver is None and options.jdbc_db is not None:
  411. # parser.error("Option --jdbc-db is used only in pair with --jdbc-driver")
  412. #elif options.jdbc_driver is not None and options.jdbc_db is None:
  413. # parser.error("Option --jdbc-driver is used only in pair with --jdbc-db")
  414. if options.debug:
  415. sys.frozen = 'windows_exe' # Fake py2exe so we can debug
  416. if len(args) == 0:
  417. print parser.print_help()
  418. parser.error("No action entered")
  419. action = args[0]
  420. if action == UPGRADE_STACK_ACTION:
  421. possible_args_numbers = [2,4] # OR
  422. else:
  423. possible_args_numbers = [1]
  424. matches = 0
  425. for args_number_required in possible_args_numbers:
  426. matches += int(len(args) == args_number_required)
  427. if matches == 0:
  428. print parser.print_help()
  429. possible_args = ' or '.join(str(x) for x in possible_args_numbers)
  430. parser.error("Invalid number of arguments. Entered: " + str(len(args)) + ", required: " + possible_args)
  431. options.exit_message = "Ambari Server '%s' completed successfully." % action
  432. need_restart = True
  433. try:
  434. if action == SETUP_ACTION:
  435. setup(options)
  436. svcsetup()
  437. elif action == START_ACTION:
  438. svcstart()
  439. elif action == PSTART_ACTION:
  440. start(options)
  441. elif action == STOP_ACTION:
  442. svcstop()
  443. elif action == RESET_ACTION:
  444. reset(options, AmbariServerService)
  445. elif action == STATUS_ACTION:
  446. svcstatus(options)
  447. elif action == UPGRADE_ACTION:
  448. upgrade(options)
  449. # elif action == UPGRADE_STACK_ACTION:
  450. # stack_id = args[1]
  451. # repo_url = None
  452. # repo_url_os = None
  453. #
  454. # if len(args) > 2:
  455. # repo_url = args[2]
  456. # if len(args) > 3:
  457. # repo_url_os = args[3]
  458. #
  459. # upgrade_stack(options, stack_id, repo_url, repo_url_os)
  460. elif action == LDAP_SETUP_ACTION:
  461. setup_ldap()
  462. elif action == SETUP_SECURITY_ACTION:
  463. need_restart = setup_security(options)
  464. else:
  465. parser.error("Invalid action")
  466. if action in ACTION_REQUIRE_RESTART and need_restart:
  467. status, stateDesc = is_server_running(AmbariServerService)
  468. if status:
  469. print 'NOTE: Restart Ambari Server to apply changes' + \
  470. ' ("ambari-server restart|stop|start")'
  471. if options.warnings:
  472. for warning in options.warnings:
  473. print_warning_msg(warning)
  474. pass
  475. options.exit_message = "Ambari Server '%s' completed with warnings." % action
  476. pass
  477. except FatalException as e:
  478. if e.reason is not None:
  479. print_error_msg("Exiting with exit code {0}. \nREASON: {1}".format(e.code, e.reason))
  480. sys.exit(e.code)
  481. except NonFatalException as e:
  482. options.exit_message = "Ambari Server '%s' completed with warnings." % action
  483. if e.reason is not None:
  484. print_warning_msg(e.reason)
  485. if options.exit_message is not None:
  486. print options.exit_message
  487. if __name__ == "__main__":
  488. try:
  489. main()
  490. except (KeyboardInterrupt, EOFError):
  491. print("\nAborting ... Keyboard Interrupt.")
  492. sys.exit(1)