ambari install逻辑详解[三]
# 3.2.3 install 过程详细解析
在 execute() 方法中,当命令名称为 install 时,会调用组件的 install 方法。下面我们逐步解析 install 过程的执行机制。
# 3.2.3.1 install 方法的调用逻辑
首先在 execute() 中,通过以下逻辑选择了 install 方法:
method = self.choose_method_to_execute(self.command_name)
假设 command_name 是 "install",那么 method 将会对应到 self.install()。
在 choose_method_to_execute 方法中,它会根据传入的 command_name 从当前类中动态获取到 install 方法并返回供后续调用。
然后,在 execute() 方法中:
with Environment(self.basedir, tmp_dir=Script.tmp_dir) as env:
if not self.is_hook():
self.execute_prefix_function(self.command_name, 'pre', env)
method(env)
if not self.is_hook():
self.execute_prefix_function(self.command_name, 'post', env)
2
3
4
5
6
7
8
通过 method(env),调用了实际的 install 方法,并且在调用之前和之后分别执行了 pre_install 和 post_install 钩子。
提示
这种写法确保每次调用 install 都自动带上前置检查与后置收尾,方便企业场景下插入环境自检、自动校验、后置通知等一系列业务流程。
# 3.2.3.2 组件中的 install 方法
以 Kafka 为例,kafka_broker.py 中的 install 方法代码如下:
class KafkaBroker(Script):
def install(self, env):
self.install_packages(env)
2
3
可以看到,KafkaBroker 类中的 install 方法直接调用了父类 Script 中的 install_packages 方法。
笔记
- 绝大多数 Ambari 组件的 install 方法都采用这种设计,调用
install_packages可以统一支持包列表下发、操作系统适配、参数透传等全流程。 - 这种封装简化了各类组件 install 代码,也减少了维护成本。
# 3.2.3.3 Script 类的 install_packages 方法
Script 类中的 install_packages 负责处理安装任务:
def install_packages(self, env):
"""
List of packages that are required by service is received from the server
as a command parameter. The method installs all packages from this list
exclude_packages - list of regexes (possibly raw strings as well), the
packages which match the regex won't be installed.
NOTE: regexes don't have Python syntax, but simple package regexes which support only * and .* and ?
"""
config = self.get_config()
if 'host_sys_prepped' in config['ambariLevelParams']:
# do not install anything on sys-prepped host
if config['ambariLevelParams']['host_sys_prepped'] is True:
Logger.info("Node has all packages pre-installed. Skipping.")
return
pass
try:
package_list_str = config['commandParams']['package_list']
agent_stack_retry_on_unavailability = bool(config['ambariLevelParams']['agent_stack_retry_on_unavailability'])
agent_stack_retry_count = int(config['ambariLevelParams']['agent_stack_retry_count'])
if isinstance(package_list_str, basestring) and len(package_list_str) > 0:
package_list = json.loads(package_list_str)
for package in package_list:
if self.check_package_condition(package):
name = self.format_package_name(package['name'])
# HACK: On Windows, only install ambari-metrics packages using Choco Package Installer
# TODO: Update this once choco packages for hadoop are created. This is because, service metainfo.xml support
# <osFamily>any<osFamily> which would cause installation failure on Windows.
if OSCheck.is_windows_family():
if "ambari-metrics" in name:
Package(name)
else:
Package(name,
retry_on_repo_unavailability=agent_stack_retry_on_unavailability,
retry_count=agent_stack_retry_count)
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
核心逻辑:
- 读取
package_list:从commandParams中提取package_list,这是由ambari-server传递给ambari-agent的安装包列表。package_list通常包含一个 JSON 字符串,列出需要安装的软件包。 - 解析和检查:使用
json.loads将package_list解析为实际的 Python 列表,并通过check_package_condition方法来判断该包是否符合安装条件。 - 调用
Package资源:对于每个符合条件的软件包,调用Package资源类来执行安装。
提示
这种机制支持了:
- 按需选择性安装(可插入条件检查)
- 支持 agent 自带重试机制
- 兼容 Windows/类 Unix 跨平台场景
- 支持未来自动跳过 sys-prepped 已装环境,灵活适配多云和镜像场景
# 3.2.3.4 Package 资源类解析
Package 类是一个资源管理类,它专门用于处理软件包的安装过程。它被设计为通过环境自动调用合适的安装逻辑:

但是实例化是父类Resource的方法
def __new__(cls, name, env=None, provider=None, **kwargs):
if isinstance(name, list):
names_list = name[:]
while len(names_list) != 1:
cls(names_list.pop(0), env, provider, **kwargs)
name = names_list[0]
env = env or Environment.get_instance()
provider = provider or getattr(cls, 'provider', None)
r_type = cls.__name__
if r_type not in env.resources:
env.resources[r_type] = {}
obj = super(Resource, cls).__new__(cls)
env.resources[r_type][name] = obj
env.resource_list.append(obj)
return obj
def __init__(self, name, env=None, provider=None, **kwargs):
if isinstance(name, list):
name = name[-1]
if hasattr(self, 'name'):
return
self.env = env or Environment.get_instance()
self.name = name
self.provider = provider or getattr(self, 'provider', None)
self.arguments = {}
for key, value in kwargs.items():
try:
arg = self._arguments[key]
except KeyError:
raise Fail("%s received unsupported argument %s" % (self, key))
else:
try:
self.arguments[key] = arg.validate(value)
except InvalidArgument, exc:
raise InvalidArgument("%s %s" % (self, exc))
if not self.env.test_mode:
self.env.run()
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
详细解析:
Package继承自Resource类,默认的action被设置为install,表示此资源的主要功能就是安装软件包。- 当
Package被实例化时,env.run_action(self, self.action)会被调用,这意味着它会执行install这一操作。 - 通过这种抽象,将具体的安装操作交由
Environment类和Provider来完成,从而实现了更强的扩展性。

笔记
这种资源化/自动分派机制一方面兼容 Python 领域最佳实践(类似 Ansible Resource),另一方面也为未来的资源二次开发、平台迁移(如 Kubernetes CRD)留足了空间。
# 3.2.3.5 使用 Environment 来调用 find_provider
在 Environment 类中,run_action 方法用于根据资源类型选择并执行对应的 Provider:

逻辑解读:
find_provider会找到与资源对应的Provider类,例如PackageProvider。- 然后,利用
getattr获取Provider中对应的action方法(例如action_install),并调用执行。 - 这种机制允许根据环境动态地调整执行逻辑,使代码更加灵活。
提示
所以用户无需关心底层是 apt/yum 还是 zypper,Provider 系统自动适配本地平台,极大降低维护和扩展成本。
# 3.2.3.6 find_provider 函数详解
find_provider 方法的作用是根据当前系统的操作环境,动态选择合适的 Provider 类来执行操作(比如安装软件包)。:

主要步骤:
输入检查:
- 接收三个参数:
env(系统环境)、resource(资源类型),和一个可选的class_path(指定Provider路径)。
- 接收三个参数:
查找
Provider:- 如果没有明确的
class_path,方法会在PROVIDERS和LIBRARY_PROVIDERS中查找。 - 根据系统的
os_family(比如RedHat或Debian),找到与资源类型对应的Provider类。
- 如果没有明确的
动态加载:
- 找到
class_path后,通过动态导入的方式加载对应的Provider类,确保可以在不同系统上执行正确的操作。
- 找到
笔记
这一步确保了不同 Linux 发行版甚至 Windows 也能用同一套安装脚本,实现一套代码、多端适配。
# 3.2.3.7 PackageProvider 和实际的安装执行
文件位置:ambari-common/src/main/python/resource_management/core/providers/packaging.py
接下来的 action_install 会实际调用操作系统的命令行工具完成安装:
class PackageProvider(Provider):
def __init__(self, *args, **kwargs):
super(PackageProvider, self).__init__(*args, **kwargs)
self._pkg_manager = ManagerFactory.get()
def action_install(self):
package_name = self.get_package_name_with_version()
self._pkg_manager.install_package(package_name, self.__create_context())
def action_upgrade(self):
package_name = self.get_package_name_with_version()
self._pkg_manager.upgrade_package(package_name, self.__create_context())
def action_remove(self):
package_name = self.get_package_name_with_version()
self._pkg_manager.remove_package(package_name, self.__create_context())
def __create_context(self):
"""
Build RepoCallContext from Resource properties
"""
return RepoCallContext(
ignore_errors=self.resource.ignore_failures,
use_repos=self.resource.use_repos,
skip_repos=self.resource.skip_repos,
log_output=True if self.resource.logoutput is None or self.resource.logoutput is True else False,
retry_count=self.resource.retry_count,
retry_sleep=self.resource.retry_sleep,
retry_on_repo_unavailability=self.resource.retry_on_repo_unavailability,
retry_on_locked=self.resource.retry_on_locked
)
def get_package_name_with_version(self):
if self.resource.version:
return self.resource.package_name + '-' + self.resource.version
else:
return self.resource.package_name
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
Manager 会进行统一管理

对于具体实现,例如 YumManager:

功能说明:
PackageProvider的action_install会利用_pkg_manager的install_package方法。_pkg_manager可能是YumManager或者AptManager,它们封装了系统命令行工具(如yum或apt-get)的具体调用。

提示
无论环境是 RHEL/CentOS/Ubuntu/SLES,最终安装动作都交给本地包管理器执行,实现了平台无关的“一键式”体验。
# 4. 最佳实践与技巧 💡
# 4.1 优化配置技巧
在设计和编写 Ambari 组件的 Python 脚本时,我们经常需要在安装、启动、停止等关键任务之前或之后执行额外的业务逻辑。
提示
为此,Ambari 提供了 pre_ 和 post_ 方法机制,让你可以灵活地在主流程前后插入自定义逻辑,实现自动化、企业级的流程控制。
例如:
- 在组件安装前执行系统检查,提前终止不合规安装,避免浪费资源;
- 在安装完成后自动清理临时文件、初始化数据或生成报告,让组件上线更自动化;
- 升级前后执行兼容性检查或配置变更,保证平滑升级体验。
实践场景举例:
- 安装前验证配置
- 在
pre_install方法中,验证依赖包、必要配置,发现问题立即终止,提升安装的安全性与成功率。
- 在
- 安装后自动化任务
- 在
post_install中触发数据迁移、初始化操作或环境收尾,无需人工介入,效率更高。
- 在
- 跨版本升级处理
- 通过
pre_upgrade、post_upgrade方法处理版本冲突、兼容性检查、配置平滑切换等,保障升级过程稳定。
- 通过
笔记
这些 pre_ 和 post_ 方法不仅适用于 install 操作,也可以扩展到 start、stop、restart
等所有生命周期节点。借助这种自定义机制,你可以让集群部署和管理流程变得更细致、更安全、更契合业务场景。
# 5. 总结与延伸学习 🚀
# 5.1 内容回顾
本篇文章系统梳理了 Ambari 组件的执行逻辑,尤其是通过自定义 Python 脚本实现多种运维自动化任务的方法,内容包括:
执行流程解析:
- 从 Ambari
install命令切入,分析了核心的execute函数; - 解析了命令参数、环境初始化、组件主流程以及
pre_和post_方法的自动化逻辑插入点。
- 从 Ambari
安装过程详解:
- 以 Kafka 组件为例,详细剖析了如何通过
Script类的install_packages实现包的自动化安装; - 拆解了
Package资源执行原理,以及如何动态选取Provider(如 YumManager/AptManager)来适配不同操作系统。
- 以 Kafka 组件为例,详细剖析了如何通过
代码执行链路梳理:
KafkaBroker.install(env)
↓
Script.install_packages(env)
↓
Environment.run_action(self, action) # action 为 "install"
↓
find_provider(self, resource, provider) # 找到相应的 PackageProvider 类
↓
PackageProvider.action_install()
↓
YumManager.install_package(name) 或 AptManager.install_package(name)
2
3
4
5
6
7
8
9
10
11
代码逻辑分层:
- 各关键节点都配有分层代码示例和详细解读,让执行机制、扩展点一目了然;
- 通过
pre和post方法介绍,帮助读者在各操作阶段插入定制化运维逻辑。
自定义
pre_和post_方法:- 展示了如何用这些方法进行前置检查、日志目录准备、版本兼容等一站式操作,大幅提升了脚本自动化能力。
find_provider函数解析:- 详细说明了根据操作系统与资源类型,如何自动定位最优 Provider,实现平台无关的包管理操作。
# 5.2 后续学习方向
通过本章内容,你已经初步掌握了 Ambari 组件的执行逻辑和自定义自动化脚本的设计思路。 为了进一步深化对 Ambari 运维体系的理解,建议继续关注以下进阶主题:
提示
深入学习 stack-hooks 的最佳实践:
- 例如,如何通过公用 stack-hooks 实现 distro-select 的版本标记、批量环境自定义等运维场景。
- 01
- Ambari开启Kerberos认证加密类型错误 Kylin V1011-05
- 02
- KERBEROS SERVICE CHECK 报错11-04