Landscape 源码分析

概述

Landscape 是一个集群监控管理软件,它可以作为 web 服务来使用或者直接使用 API。Landscape Server 可以通过 Canonical 作为托管解决方案或者 Software-as-a-Server 模型,也可以自行托管。Landscape Client 安装在 Ubuntu 上,并向 Server 注册。
Landscape 自动化了整个 Ubuntu 系统的安全补丁、审计、访问管理和合规性任务。

Landscape 源代码使用了 Twisted 事件驱动网络引擎。

代码结构

概括

在 landscape 包的init.py中我们看到定义了一些变量,这些变量几乎都和版本号有关,这些变量类似于 C 语言中的全局宏定义。

运行模式

Landscape-client 可以root用户运行,进而可以使用一些高级管理特性,如果不需要使用这种特性时,可以使用landscape用户运行。通过修改/etc/default/landscape-client/etc/landscape/client.conf文件可以办到(具体细节见项目代码README)。

watchdog 模块

代码位置:landscape/client/watchdog.py

watchdog 是最高层的代码,它清理运行环境,载入配置文件,然后启动 ractor 循环。

a. clean_environment():该函数清除一些危险和敏感的变量。
b. 载入配置文件 : 和配置文件相关的工作被抽象为一系列具有继承关系的类,有些类在不同的模块中被重用。

classDiagram
    landscape_lib_BaseConfiguration <-- landscape_client_deployment_BaseConfiguration
    landscape_client_deployment_BaseConfiguration <-- landscape_client_deployment_Configuration
    landscape_client_deployment_Configuration <-- landscape_client_watchdog_WatchDogConfiguration

c. 执行用户限制(只允许landscape或者root用户执行);初始化 logging
d. 实例化WatchDogService服务, 并成为application的子服务,启动ractor.

WatchDogService

WatchDogService继承自twisted.service,实例化时传递WatchDogConfiguration配置参数到私有实例变量_config

a. resource包来自于标准库,用来测试和控制系统资源的分配。soft limithard limit的区别,只有root进程可以提升hard limit(参考Linux/Unix系统编程手册)。 资源类型包括 CPU 运行时间、可以生成文件的最大空间、进程堆/栈的大小、打开文件描述符的数量(RLIMIT_NOFILE)等等。
b. WatchDogServicestartService方法首先生成BootStrapList中的文件或者目录,然后设置资源限制,最后生成已经callback激发的Defered对象,
该对象增加的回调链:

watchdog.check_running() | past
start_if_not_running() | die()

watchdog是在WatchDogService初始化时WatchDog类的实例对象。

start_if_not_running方法会调用_daemonize()方法,该方法根据实际参数判断自己是否要成为一个daemon进程,如果是的话,就调用daemonize function,该函数会调用 os 的底层 API,调用两次fork(),并让父进程自杀,其他具体细节可参考 Linux/Unix系统编程手册。 最后调用watchdogstart方法,它根据条件启动其他daemons并进行监控。

e. stopService方法
它主要工作是调用watchdogrequest_exit方法,该方法会做比较精细复杂的工作来小心地让自己和其他daemons终止,比如避免重启。

f. 不管是startService还是stopService方法返回的都是Defered对象或者DeferedList对象,这些对象会被Twisted内部使用。

WatchDog 类

WatchDog类负责启动其他所有的daemons(包括brokerMonitorManager等)并确保它们运行。这些daemons运行在不同的ractor循环中,使用AMP协议通信。 landscape_reactorEventHandlingReactor类的实例对象。

a. EventHandlingReactor类封装了twisted.internet.reactor,继承自EventHandlingReactorMixin类,增加事件处理特性。 其中callInThread来源于Twisted对于多线程的支持。Twisted更多应用于 I/O 密集型应用,即任务的计算任务不会持续很长时间,但是如果有一个
任务很耗时的话,Twistedractor循环此时完全被该任务占用,其他任务会面临饥饿的问题。因此将该任务放到辅助线程中去执行,reactor主循环可以得到解放。callFromThread中的function可以立即在reactor线程中执行,但不保证线程安全,即reactor立即被切换?如果它正在执行任务如何?。如果该 function一直在运行,reactor被阻塞,其他任务会面临饥饿问题。参看链接2和3。

b. EventHandingReactorMixin类负责激活在被标识事件上绑定的handlers。重要的一点是这些事件的处理是同步的还是异步的? call_on方法注册事件handler,一个事件类型可以绑定多个handler,并根据handler的优先级排序。 fair方法根据优先级顺序激发一个事件类型的所有handler,并返回所有handler的执行结果。 这些执行结果或许是Defered,即它的结果还不能立即得到。 cancel_call方法删除事件的某个handler绑定。

c. EventID类,对于每个handler只对应一种事件类型,因此(event_type, (handler, priority))可以唯一标识一个handler

d. WatchDog注册了SIGUSR1信号的handler,该handler会通知所有daemons调用rotate_logs()

e. check_running方法检测哪些daemons正在运行,结果放在一个List中,但结果本身是一个Defered对象。gather_results将所有Defereds放到DeferedList对象中管理。DeferdList会等待所有其管理的Defereds回调链完成后再运行自己的回调链,这样正好实现异步形式的check_running方法。

f. start方法启动所有其他的daemons,并调用start_minitoring监控它们的进程状态。start_monitoring方法会启动一个回调_check方法,_check方法在完成一次check后增加自己到reactor回调链中,延时 5 秒。当检测到某个daemon在 5 次探测中均没有回复,WatchDog判断该daemon已经死掉,所以接下来就重启它,并清零探测失败计数器。

Daemon类和其子类

WatchedProcessProtocol类

amp 模块

Service 相关模块和类

Monitor模块

Manager模块

Bootstrap相关的类

Configuration相关的类

BootstrapList类是其他类列表的分发器,这个列表中的元素甚至可以是它自己的实例对象,遵循闭包设计。
BootstrapPathBootsrapFileBootstrapDirectory的父类,它通过模块生成文件路径(或文件或目录),并设置其用户属性(chown)和访问权限(chmod)
BootstrapFile对应文件,BootstrapDirectory对应目录。

日志

遵循分离设计,重要的是watchdogmonitorbrokermanager都有自己的logger,因此它们的日志可以分开处理,但仍然使用相同的logging APIs