| #!/usr/bin/env python |
| |
| ''' |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| ''' |
| |
| import optparse |
| import sys |
| import os |
| import signal |
| |
| from ambari_commons.exceptions import FatalException, NonFatalException |
| from ambari_commons.logging_utils import set_verbose, set_silent, \ |
| print_info_msg, print_warning_msg, print_error_msg, set_debug_mode_from_options |
| from ambari_commons.os_check import OSConst |
| from ambari_commons.os_family_impl import OsFamilyFuncImpl, OsFamilyImpl |
| from ambari_commons.os_utils import remove_file |
| from ambari_server.BackupRestore import main as BackupRestore_main |
| from ambari_server.dbConfiguration import DATABASE_NAMES |
| from ambari_server.serverConfiguration import configDefaults, get_ambari_properties, PID_NAME |
| from ambari_server.serverUtils import is_server_runing, refresh_stack_hash |
| from ambari_server.serverSetup import reset, setup, setup_jce_policy |
| from ambari_server.serverUpgrade import upgrade, upgrade_stack, set_current |
| from ambari_server.setupHttps import setup_https |
| |
| from ambari_server.setupActions import BACKUP_ACTION, LDAP_SETUP_ACTION, LDAP_SYNC_ACTION, PSTART_ACTION, \ |
| REFRESH_STACK_HASH_ACTION, RESET_ACTION, RESTORE_ACTION, SETUP_ACTION, SETUP_SECURITY_ACTION, START_ACTION, \ |
| STATUS_ACTION, STOP_ACTION, UPGRADE_ACTION, UPGRADE_STACK_ACTION, SETUP_JCE_ACTION, SET_CURRENT |
| from ambari_server.setupSecurity import setup_ldap, sync_ldap, setup_master_key, setup_ambari_krb5_jaas |
| from ambari_server.userInput import get_validated_string_input |
| |
| from ambari_server_main import server_process_main |
| |
| |
| class UserActionPossibleArgs(object): |
| def __init__(self, i_fn, i_possible_args_numbers, *args, **kwargs): |
| self.fn = i_fn |
| self.possible_args_numbers = i_possible_args_numbers |
| self.args = args |
| self.kwargs = kwargs |
| self.need_restart = False |
| |
| def execute(self): |
| self.fn(*self.args, **self.kwargs) |
| |
| class UserAction(UserActionPossibleArgs): |
| def __init__(self, i_fn, *args, **kwargs): |
| super(UserAction, self).__init__(i_fn, [1], *args, **kwargs) |
| |
| class UserActionRestart(UserAction): |
| def __init__(self, i_fn, *args, **kwargs): |
| super(UserActionRestart, self).__init__(i_fn, *args, **kwargs) |
| |
| def execute(self): |
| self.need_restart = self.fn(*self.args, **self.kwargs) |
| |
| |
| def winsetup(options): |
| from ambari_windows_service import svcsetup |
| |
| setup(options) |
| svcsetup() |
| |
| # |
| # Starts the Ambari Server as a standalone process. |
| # Ensures only one instance of the process is running. |
| # If this is the second instance of the process, the function fails. |
| # |
| @OsFamilyFuncImpl(OSConst.WINSRV_FAMILY) |
| def start(options): |
| from ambari_windows_service import AmbariServerService, ctrlHandler |
| |
| status, pid = is_server_runing() |
| if status: |
| err = "Ambari Server is already running." |
| raise FatalException(1, err) |
| |
| AmbariServerService.set_ctrl_c_handler(ctrlHandler) |
| |
| #Run as a normal process. Invoke the ServiceMain directly. |
| childProc = server_process_main(options) |
| |
| childProc.wait() |
| |
| pid_file_path = os.path.join(configDefaults.PID_DIR, PID_NAME) |
| remove_file(pid_file_path) |
| |
| # |
| # Starts the Ambari Server. |
| # Ensures only one instance of the process is running. |
| # If this is the second instance of the process, the function fails. |
| # |
| @OsFamilyFuncImpl(OsFamilyImpl.DEFAULT) |
| def start(args): |
| status, pid = is_server_runing() |
| if status: |
| err = "Ambari Server is already running." |
| raise FatalException(1, err) |
| |
| server_process_main(args) |
| |
| |
| # |
| # Starts the Ambari Server as a service. |
| # Start the server as a Windows service. If the Ambari server is |
| # not registered as a service, the function fails. By default, only one instance of the service can |
| # possibly run. |
| # |
| def svcstart(): |
| from ambari_windows_service import AmbariServerService |
| |
| AmbariServerService.Start() |
| pass |
| |
| |
| # |
| # Stops the Ambari Server service. |
| # |
| @OsFamilyFuncImpl(OSConst.WINSRV_FAMILY) |
| def stop(): |
| from ambari_windows_service import AmbariServerService |
| |
| AmbariServerService.Stop() |
| |
| # |
| # Stops the Ambari Server. |
| # |
| @OsFamilyFuncImpl(OsFamilyImpl.DEFAULT) |
| def stop(args): |
| if (args != None): |
| args.exit_message = None |
| |
| status, pid = is_server_runing() |
| |
| if status: |
| try: |
| os.killpg(os.getpgid(pid), signal.SIGKILL) |
| except OSError, e: |
| print_info_msg("Unable to stop Ambari Server - " + str(e)) |
| return |
| pid_file_path = os.path.join(configDefaults.PID_DIR, PID_NAME) |
| os.remove(pid_file_path) |
| print "Ambari Server stopped" |
| else: |
| print "Ambari Server is not running" |
| |
| |
| # |
| # The Ambari Server status. |
| # |
| @OsFamilyFuncImpl(OSConst.WINSRV_FAMILY) |
| def status(args): |
| from ambari_windows_service import AmbariServerService |
| |
| args.exit_message = None |
| |
| statusStr = AmbariServerService.QueryStatus() |
| print "Ambari Server is " + statusStr |
| |
| # |
| # The Ambari Server status. |
| # |
| @OsFamilyFuncImpl(OsFamilyImpl.DEFAULT) |
| def status(args): |
| args.exit_message = None |
| status, pid = is_server_runing() |
| pid_file_path = os.path.join(configDefaults.PID_DIR, PID_NAME) |
| if status: |
| print "Ambari Server running" |
| print "Found Ambari Server PID: " + str(pid) + " at: " + pid_file_path |
| else: |
| print "Ambari Server not running. Stale PID File at: " + pid_file_path |
| |
| |
| def refresh_stack_hash_action(): |
| properties = get_ambari_properties() |
| refresh_stack_hash(properties) |
| |
| |
| @OsFamilyFuncImpl(OSConst.WINSRV_FAMILY) |
| def create_setup_security_actions(args): |
| action_list = [ |
| ['Enable HTTPS for Ambari server.', UserActionRestart(setup_https, args)], |
| ['Encrypt passwords stored in ambari.properties file.', UserAction(setup_master_key)], |
| ['Setup Ambari kerberos JAAS configuration.', UserAction(setup_ambari_krb5_jaas)], |
| ] |
| return action_list |
| |
| @OsFamilyFuncImpl(OsFamilyImpl.DEFAULT) |
| def create_setup_security_actions(args): |
| action_list = [ |
| ['Enable HTTPS for Ambari server.', UserActionRestart(setup_https, args)], |
| ['Encrypt passwords stored in ambari.properties file.', UserAction(setup_master_key)], |
| ['Setup Ambari kerberos JAAS configuration.', UserAction(setup_ambari_krb5_jaas)], |
| ] |
| return action_list |
| |
| def setup_security(args): |
| actions = create_setup_security_actions(args) |
| |
| #Print menu options |
| print '=' * 75 |
| print 'Choose one of the following options: ' |
| |
| iAction = 0 |
| for actionDesc in actions: |
| iAction += 1 |
| print ' [{0}] {1}'.format(iAction, actionDesc[0]) |
| print '=' * 75 |
| |
| choice_prompt = 'Enter choice, (1-{0}): '.format(iAction) |
| choice_re = '[1-{0}]'.format(iAction) |
| choice = get_validated_string_input(choice_prompt, '0', choice_re, |
| 'Invalid choice', False, False) |
| |
| try: |
| actionDesc = actions[int(choice) - 1] |
| except IndexError: |
| raise FatalException('Unknown option for setup-security command.') |
| |
| action = actionDesc[1] |
| action.execute() |
| |
| return action.need_restart |
| |
| |
| # |
| # Backup / Restore |
| # |
| def get_backup_path(args): |
| if len(args) == 2: |
| path = args[1] |
| else: |
| path = None |
| return path |
| |
| def backup(args): |
| print "Backup requested." |
| backup_command = ["BackupRestore", 'backup'] |
| path = get_backup_path(args) |
| if not path is None: |
| backup_command.append(path) |
| |
| BackupRestore_main(backup_command) |
| |
| def restore(args): |
| print "Restore requested." |
| restore_command = ["BackupRestore", 'restore'] |
| path = get_backup_path(args) |
| if not path is None: |
| restore_command.append(path) |
| |
| BackupRestore_main(restore_command) |
| |
| |
| @OsFamilyFuncImpl(OSConst.WINSRV_FAMILY) |
| def init_parser_options(parser): |
| parser.add_option('-f', '--init-script-file', dest="init_db_script_file", |
| default="resources" + os.sep + "Ambari-DDL-SQLServer-CREATE.sql", |
| help="File with database setup script") |
| parser.add_option('-r', '--drop-script-file', dest="cleanup_db_script_file", |
| default="resources" + os.sep + "Ambari-DDL-SQLServer-DROP.sql", |
| help="File with database cleanup script") |
| parser.add_option('-j', '--java-home', dest="java_home", default=None, |
| help="Use specified java_home. Must be valid on all hosts") |
| parser.add_option("-v", "--verbose", |
| action="store_true", dest="verbose", default=False, |
| help="Print verbose status messages") |
| parser.add_option("-s", "--silent", |
| action="store_true", dest="silent", default=False, |
| help="Silently accepts default prompt values") |
| parser.add_option('-g', '--debug', action="store_true", dest='debug', default=False, |
| help="Start ambari-server in debug mode") |
| parser.add_option('-y', '--suspend-start', action="store_true", dest='suspend_start', default=False, |
| help="Freeze ambari-server Java process at startup in debug mode") |
| |
| parser.add_option('-a', '--databasehost', dest="database_host", default=None, |
| help="Hostname of database server") |
| parser.add_option('-n', '--databaseport', dest="database_port", default=None, |
| help="Database server listening port") |
| parser.add_option('-d', '--databasename', dest="database_name", default=None, |
| help="Database/Schema/Service name or ServiceID") |
| parser.add_option('-w', '--windowsauth', action="store_true", dest="database_windows_auth", default=None, |
| help="Integrated Windows authentication") |
| parser.add_option('-u', '--databaseusername', dest="database_username", default=None, |
| help="Database user login") |
| parser.add_option('-p', '--databasepassword', dest="database_password", default=None, |
| help="Database user password") |
| parser.add_option('--jdbc-driver', default=None, dest="jdbc_driver", |
| help="Specifies the path to the JDBC driver JAR file") |
| # -b, -i, -k and -x the remaining available short options |
| # -h reserved for help |
| |
| @OsFamilyFuncImpl(OsFamilyImpl.DEFAULT) |
| def init_parser_options(parser): |
| optparse.Option('-f', '--init-script-file', |
| default='/var/lib/ambari-server/' |
| 'resources/Ambari-DDL-Postgres-EMBEDDED-CREATE.sql', |
| help="File with setup script") |
| parser.add_option('-r', '--drop-script-file', default="/var/lib/" |
| "ambari-server/resources/" |
| "Ambari-DDL-Postgres-EMBEDDED-DROP.sql", |
| help="File with drop script") |
| parser.add_option('-u', '--upgrade-script-file', default="/var/lib/" |
| "ambari-server/resources/upgrade/ddl/" |
| "Ambari-DDL-Postgres-UPGRADE-1.3.0.sql", |
| help="File with upgrade script") |
| parser.add_option('-t', '--upgrade-stack-script-file', default="/var/lib/" |
| "ambari-server/resources/upgrade/dml/" |
| "Ambari-DML-Postgres-UPGRADE_STACK.sql", |
| help="File with stack upgrade script") |
| parser.add_option('-j', '--java-home', default=None, |
| help="Use specified java_home. Must be valid on all hosts") |
| parser.add_option("-v", "--verbose", |
| action="store_true", dest="verbose", default=False, |
| help="Print verbose status messages") |
| parser.add_option("-s", "--silent", |
| action="store_true", dest="silent", default=False, |
| help="Silently accepts default prompt values") |
| parser.add_option('-g', '--debug', action="store_true", dest='debug', default=False, |
| help="Start ambari-server in debug mode") |
| parser.add_option('-y', '--suspend-start', action="store_true", dest='suspend_start', default=False, |
| help="Freeze ambari-server Java process at startup in debug mode") |
| parser.add_option('--all', action="store_true", default=False, help="LDAP sync all option. Synchronize all LDAP users and groups.", |
| dest="ldap_sync_all") |
| parser.add_option('--existing', action="store_true", default=False, |
| help="LDAP sync existing option. Synchronize existing Ambari users and groups only.", dest="ldap_sync_existing") |
| parser.add_option('--users', default=None, help="LDAP sync users option. Specifies the path to a CSV file of user names to be synchronized.", |
| dest="ldap_sync_users") |
| parser.add_option('--groups', default=None, help="LDAP sync groups option. Specifies the path to a CSV file of group names to be synchronized.", |
| dest="ldap_sync_groups") |
| parser.add_option('--database', default=None, help="Database to use embedded|oracle|mysql|postgres", dest="dbms") |
| parser.add_option('--databasehost', default=None, help="Hostname of database server", dest="database_host") |
| parser.add_option('--databaseport', default=None, help="Database port", dest="database_port") |
| parser.add_option('--databasename', default=None, help="Database/Service name or ServiceID", |
| dest="database_name") |
| parser.add_option('--postgresschema', default=None, help="Postgres database schema name", |
| dest="postgres_schema") |
| parser.add_option('--databaseusername', default=None, help="Database user login", dest="database_username") |
| parser.add_option('--databasepassword', default=None, help="Database user password", dest="database_password") |
| parser.add_option('--sidorsname', default="sname", help="Oracle database identifier type, Service ID/Service " |
| "Name sid|sname", dest="sid_or_sname") |
| parser.add_option('--jdbc-driver', default=None, help="Specifies the path to the JDBC driver JAR file for the " \ |
| "database type specified with the --jdbc-db option. Used only with --jdbc-db option.", |
| dest="jdbc_driver") |
| parser.add_option('--jdbc-db', default=None, help="Specifies the database type [postgres|mysql|oracle] for the " \ |
| "JDBC driver specified with the --jdbc-driver option. Used only with --jdbc-driver option.", |
| dest="jdbc_db") |
| parser.add_option('--cluster-name', default=None, help="Cluster name", dest="cluster_name") |
| parser.add_option('--version-display-name', default=None, help="Display name of desired repo version", dest="desired_repo_version") |
| |
| |
| @OsFamilyFuncImpl(OSConst.WINSRV_FAMILY) |
| def are_cmd_line_db_args_blank(options): |
| if (options.database_host is None \ |
| and options.database_name is None \ |
| and options.database_windows_auth is None \ |
| and options.database_username is None \ |
| and options.database_password is None): |
| return True |
| return False |
| |
| @OsFamilyFuncImpl(OsFamilyImpl.DEFAULT) |
| def are_cmd_line_db_args_blank(options): |
| if options.dbms is None \ |
| and options.database_host is None \ |
| and options.database_port is None \ |
| and options.database_name is None \ |
| and options.database_username is None \ |
| and options.database_password is None: |
| return True |
| return False |
| |
| |
| def are_db_auth_options_ok(db_windows_auth, db_username, db_password): |
| if db_windows_auth is True: |
| return True |
| else: |
| if db_username is not None and db_username is not "" and db_password is not None and db_password is not "": |
| return True |
| return False |
| |
| @OsFamilyFuncImpl(OSConst.WINSRV_FAMILY) |
| def are_cmd_line_db_args_valid(options): |
| if (options.database_host is not None and options.database_host is not "" \ |
| #and options.database_name is not None \ # ambari by default is ok |
| and are_db_auth_options_ok(options.database_windows_auth, |
| options.database_username, |
| options.database_password)): |
| return True |
| return False |
| |
| @OsFamilyFuncImpl(OsFamilyImpl.DEFAULT) |
| def are_cmd_line_db_args_valid(options): |
| if options.dbms is not None \ |
| and options.database_host is not None \ |
| and options.database_port is not None \ |
| and options.database_name is not None \ |
| and options.database_username is not None \ |
| and options.database_password is not None: |
| return True |
| return False |
| |
| |
| @OsFamilyFuncImpl(OSConst.WINSRV_FAMILY) |
| def init_debug(options): |
| if options.debug: |
| sys.frozen = 'windows_exe' # Fake py2exe so we can debug |
| |
| @OsFamilyFuncImpl(OsFamilyImpl.DEFAULT) |
| def init_debug(options): |
| pass |
| |
| |
| @OsFamilyFuncImpl(OSConst.WINSRV_FAMILY) |
| def fix_database_options(options, parser): |
| pass |
| |
| @OsFamilyFuncImpl(OsFamilyImpl.DEFAULT) |
| def fix_database_options(options, parser): |
| if options.dbms == 'embedded': |
| print "WARNING: HostName for postgres server " + options.database_host + \ |
| " will be ignored: using localhost." |
| options.database_host = "localhost" |
| options.dbms = 'postgres' |
| options.persistence_type = 'local' |
| options.database_index = 0 |
| elif options.dbms is not None and options.dbms not in DATABASE_NAMES: |
| parser.print_help() |
| parser.error("Unsupported Database " + options.dbms) |
| elif options.dbms is not None: |
| options.dbms = options.dbms.lower() |
| |
| # correct port |
| if options.database_port is not None: |
| correct = False |
| try: |
| port = int(options.database_port) |
| if 65536 > port > 0: |
| correct = True |
| except ValueError: |
| pass |
| if not correct: |
| parser.print_help() |
| parser.error("Incorrect database port " + options.database_port) |
| |
| # jdbc driver and db options validation |
| if options.jdbc_driver is None and options.jdbc_db is not None: |
| parser.error("Option --jdbc-db is used only in pair with --jdbc-driver") |
| elif options.jdbc_driver is not None and options.jdbc_db is None: |
| parser.error("Option --jdbc-driver is used only in pair with --jdbc-db") |
| if options.sid_or_sname.lower() not in ["sid", "sname"]: |
| print "WARNING: Valid values for sid_or_sname are 'sid' or 'sname'. Use 'sid' if the db identifier type is " \ |
| "Service ID. Use 'sname' if the db identifier type is Service Name" |
| parser.print_help() |
| exit(-1) |
| else: |
| options.sid_or_sname = options.sid_or_sname.lower() |
| |
| |
| @OsFamilyFuncImpl(OSConst.WINSRV_FAMILY) |
| def create_user_action_map(args, options): |
| action_map = { |
| SETUP_ACTION: UserAction(winsetup, options), |
| START_ACTION: UserAction(svcstart), |
| PSTART_ACTION: UserAction(start, options), |
| STOP_ACTION: UserAction(stop), |
| RESET_ACTION: UserAction(reset, options), |
| STATUS_ACTION: UserAction(status, options), |
| UPGRADE_ACTION: UserAction(upgrade, options), |
| LDAP_SETUP_ACTION: UserAction(setup_ldap), |
| SETUP_SECURITY_ACTION: UserActionRestart(setup_security, options), |
| } |
| return action_map |
| |
| @OsFamilyFuncImpl(OsFamilyImpl.DEFAULT) |
| def create_user_action_map(args, options): |
| action_map = { |
| SETUP_ACTION: UserAction(setup, options), |
| SETUP_JCE_ACTION : UserActionPossibleArgs(setup_jce_policy, [2], args), |
| START_ACTION: UserAction(start, options), |
| STOP_ACTION: UserAction(stop, options), |
| RESET_ACTION: UserAction(reset, options), |
| STATUS_ACTION: UserAction(status, options), |
| UPGRADE_ACTION: UserAction(upgrade, options), |
| UPGRADE_STACK_ACTION: UserActionPossibleArgs(upgrade_stack, [2, 4], args), |
| LDAP_SETUP_ACTION: UserAction(setup_ldap), |
| LDAP_SYNC_ACTION: UserAction(sync_ldap, options), |
| SET_CURRENT: UserAction(set_current, options), |
| SETUP_SECURITY_ACTION: UserActionRestart(setup_security, options), |
| REFRESH_STACK_HASH_ACTION: UserAction(refresh_stack_hash_action), |
| BACKUP_ACTION: UserActionPossibleArgs(backup, [1, 2], args), |
| RESTORE_ACTION: UserActionPossibleArgs(restore, [1, 2], args) |
| } |
| return action_map |
| |
| |
| # |
| # Main. |
| # |
| def main(options, args, parser): |
| # set silent |
| set_silent(options.silent) |
| |
| # debug mode |
| set_debug_mode_from_options(options) |
| init_debug(options) |
| |
| #perform checks |
| |
| options.warnings = [] |
| |
| if are_cmd_line_db_args_blank(options): |
| options.must_set_database_options = True |
| elif not are_cmd_line_db_args_valid(options): |
| parser.error('All database options should be set. Please see help for the options.') |
| else: |
| options.must_set_database_options = False |
| |
| #correct database |
| fix_database_options(options, parser) |
| |
| if len(args) == 0: |
| print parser.print_help() |
| parser.error("No action entered") |
| |
| action_map = create_user_action_map(args, options) |
| |
| action = args[0] |
| |
| try: |
| action_obj = action_map[action] |
| except KeyError: |
| parser.error("Invalid action: " + action) |
| |
| matches = 0 |
| for args_number_required in action_obj.possible_args_numbers: |
| matches += int(len(args) == args_number_required) |
| |
| if matches == 0: |
| print parser.print_help() |
| possible_args = ' or '.join(str(x) for x in action_obj.possible_args_numbers) |
| parser.error("Invalid number of arguments. Entered: " + str(len(args)) + ", required: " + possible_args) |
| |
| options.exit_message = "Ambari Server '%s' completed successfully." % action |
| |
| try: |
| action_obj.execute() |
| |
| if action_obj.need_restart: |
| pstatus, pid = is_server_runing() |
| if pstatus: |
| print 'NOTE: Restart Ambari Server to apply changes' + \ |
| ' ("ambari-server restart|stop+start")' |
| |
| if options.warnings: |
| for warning in options.warnings: |
| print_warning_msg(warning) |
| pass |
| options.exit_message = "Ambari Server '%s' completed with warnings." % action |
| pass |
| except FatalException as e: |
| if e.reason is not None: |
| print_error_msg("Exiting with exit code {0}. \nREASON: {1}".format(e.code, e.reason)) |
| sys.exit(e.code) |
| except NonFatalException as e: |
| options.exit_message = "Ambari Server '%s' completed with warnings." % action |
| if e.reason is not None: |
| print_warning_msg(e.reason) |
| |
| if options.exit_message is not None: |
| print options.exit_message |
| |
| def mainBody(): |
| parser = optparse.OptionParser(usage="usage: %prog [options] action [stack_id os]",) |
| init_parser_options(parser) |
| (options, args) = parser.parse_args() |
| |
| # set verbose |
| set_verbose(options.verbose) |
| if options.verbose: |
| main(options, args, parser) |
| else: |
| try: |
| main(options, args, parser) |
| except Exception as e: |
| print_error_msg("Unexpected {0}: {1}".format((e).__class__.__name__, str(e)) +\ |
| "\nFor more info run ambari-server with -v or --verbose option") |
| sys.exit(1) |
| |
| |
| if __name__ == "__main__": |
| try: |
| mainBody() |
| except (KeyboardInterrupt, EOFError): |
| print("\nAborting ... Keyboard Interrupt.") |
| sys.exit(1) |