Ambari Resource 01

在使用Ambari的过程中遇到了好多问题,比如删除一个cluster(使用ambari-server reset命令)后,重启Ambari Server之后一直报错,提示找不到集群。尝试各种方法之后,无法找到满意的解决之道的情况下,只好硬着头皮读读源码,了解一下Ambari的启动机制。在此记下源码阅读的笔记和心得。

首先分析一下Ambari Server的启动脚本(ambari-server.py),以便了解Ambari Server是如何启动的。

首先看入口函数

1
2
3
4
5
6
if __name__ == "__main__":
try:
mainBody()
except (KeyboardInterrupt, EOFError):
print("\nAborting ... Keyboard Interrupt.")
sys.exit(1)

没什么可说的,就是调用文件中的 mainBody() 方法。

mainBody方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
def mainBody():
#初始化命令行参数解析器
parser = optparse.OptionParser(usage="usage: %prog action [options]",)
action = sys.argv[1]
#init_action_parser方法,在脚本中会有两个方法,一个是针对windows的一个是针对linux的,所以看代码的时候需要注意(方法上使用@OsFamilyFuncImpl标示),我们这里看的是linux的
#就是对命令行解析器进行初始化,并针对行为进行进一步的初始化
init_action_parser(action, parser)
#使用命令行参数解析器,对命令行进行解析
(options, args) = parser.parse_args()
# check if only silent key set
default_options = parser.get_default_values()
silent_options = default_options
silent_options.silent = True
if options == silent_options:
options.only_silent = True
else:
options.only_silent = False
# varbose是在init_action_parser方法中设置的,对应的-v参数。是否打印状态信息
# set_varbose方法位于 ambari_commons.logging_utils中,其实就是设置全局变量_VERBOSE的值。
# set verbose
set_verbose(options.verbose)
#接下来就是调用main方法。这里目测是同一个main方法,最大的区别就是有异常处理,有待之后补充TODO--------------------???
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)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
def init_action_parser(action, parser):
#定义了参数可用的行为,如ambari-server start,其中start就是行为。这里定义了行为以及对应行为处理操作。
#这些行为的处理方法其实是进一步的初始化参数解析器,会根据对应的行为对参数解析器进行不同的初始化。
action_parser_map = {
SETUP_ACTION: init_setup_parser_options,
SETUP_JCE_ACTION: init_empty_parser_options,
START_ACTION: init_start_parser_options,
STOP_ACTION: init_empty_parser_options,
RESTART_ACTION: init_start_parser_options,
RESET_ACTION: init_reset_parser_options,
STATUS_ACTION: init_empty_parser_options,
UPGRADE_ACTION: init_empty_parser_options,
LDAP_SETUP_ACTION: init_ldap_setup_parser_options,
LDAP_SYNC_ACTION: init_ldap_sync_parser_options,
SET_CURRENT_ACTION: init_set_current_parser_options,
SETUP_SECURITY_ACTION: init_setup_security_parser_options,
REFRESH_STACK_HASH_ACTION: init_empty_parser_options,
BACKUP_ACTION: init_empty_parser_options,
RESTORE_ACTION: init_empty_parser_options,
UPDATE_HOST_NAMES_ACTION: init_empty_parser_options,
CHECK_DATABASE_ACTION: init_empty_parser_options,
ENABLE_STACK_ACTION: init_enable_stack_parser_options,
SETUP_SSO_ACTION: init_setup_sso_options,
DB_PURGE_ACTION: init_db_purge_parser_options,
INSTALL_MPACK_ACTION: init_install_mpack_parser_options,
UNINSTALL_MPACK_ACTION: init_uninstall_mpack_parser_options,
UPGRADE_MPACK_ACTION: init_upgrade_mpack_parser_options,
PAM_SETUP_ACTION: init_pam_setup_parser_options,
KERBEROS_SETUP_ACTION: init_kerberos_setup_parser_options,
}
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. For db-cleanup command, silent mode will stop ambari server.")
try:
#根据行为,做进一步的解析器初始化,我们以setup行为为例,那么setup行为的参数解析器对应的是init_setup_parser_options函数。
action_parser_map[action](parser)
except KeyError:
parser.error("Invalid action: " + action)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
@OsFamilyFuncImpl(OsFamilyImpl.DEFAULT)
def init_setup_parser_options(parser):
database_group = optparse.OptionGroup(parser, 'Database options (command need to include all options)')
database_group.add_option('--database', default=None, help="Database to use embedded|oracle|mysql|mssql|postgres|sqlanywhere", dest="dbms")
database_group.add_option('--databasehost', default=None, help="Hostname of database server", dest="database_host")
database_group.add_option('--databaseport', default=None, help="Database port", dest="database_port")
database_group.add_option('--databasename', default=None, help="Database/Service name or ServiceID",
dest="database_name")
database_group.add_option('--databaseusername', default=None, help="Database user login", dest="database_username")
database_group.add_option('--databasepassword', default=None, help="Database user password", dest="database_password")
parser.add_option_group(database_group)
jdbc_group = optparse.OptionGroup(parser, 'JDBC options (command need to include all options)')
jdbc_group.add_option('--jdbc-driver', default=None, help="Specifies the path to the JDBC driver JAR file or archive " \
"with all required files(jdbc jar, libraries and etc), for the " \
"database type specified with the --jdbc-db option. " \
"Used only with --jdbc-db option. Archive is supported only for" \
" sqlanywhere database." ,
dest="jdbc_driver")
jdbc_group.add_option('--jdbc-db', default=None, help="Specifies the database type [postgres|mysql|mssql|oracle|hsqldb|sqlanywhere] for the " \
"JDBC driver specified with the --jdbc-driver option. Used only with --jdbc-driver option.",
dest="jdbc_db")
parser.add_option_group(jdbc_group)
other_group = optparse.OptionGroup(parser, 'Other options')
other_group.add_option('-j', '--java-home', default=None,
help="Use specified java_home. Must be valid on all hosts")
other_group.add_option('--stack-java-home', dest="stack_java_home", default=None,
help="Use specified java_home for stack services. Must be valid on all hosts")
other_group.add_option('--skip-view-extraction', action="store_true", default=False, help="Skip extraction of system views", dest="skip_view_extraction")
other_group.add_option('--postgresschema', default=None, help="Postgres database schema name",
dest="postgres_schema")
other_group.add_option('--sqla-server-name', default=None, help="SQL Anywhere server name", dest="sqla_server_name")
other_group.add_option('--sidorsname', default="sname", help="Oracle database identifier type, Service ID/Service "
"Name sid|sname", dest="sid_or_sname")
other_group.add_option('--enable-lzo-under-gpl-license', action="store_true", default=False, help="Automatically accepts GPL license", dest="accept_gpl")
# the --master-key option is needed in the event passwords in the ambari.properties file are encrypted
other_group.add_option('--master-key', default=None, help="Master key for encrypting passwords", dest="master_key")
parser.add_option_group(other_group)

这个方法就是为setup的行为,做了进一步的解析器设置。

1
2
3
4
5
_VERBOSE = False
def set_verbose(newVal):
global _VERBOSE
_VERBOSE = newVal

该方法就是设置全局变量_VERBOSE的值。

main

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
def main(options, args, parser):
init_logging()
# set silent
set_silent(options.silent)
# debug mode
set_debug_mode_from_options(options)
init_debug(options)
#perform checks
options.warnings = []
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)
if action == SETUP_ACTION:
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)
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
options.exit_code = None
try:
if action in _action_option_dependence_map:
required, optional = _action_option_dependence_map[action]
for opt_str, opt_dest in required:
if hasattr(options, opt_dest) and getattr(options, opt_dest) is None:
print "Missing option {0} for action {1}".format(opt_str, action)
print_action_arguments_help(action)
print "Run ambari-server.py --help to see detailed description of each option"
raise FatalException(1, "Missing option")
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))
logger.exception(str(e))
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
if options.exit_code is not None: # not all actions may return a system exit code
sys.exit(options.exit_code)