以下是一个根据操作系统发行版来改变行为的Ansible模块的实例:

我将解释一个实现了根据操作系统来调整行为的Ansible模块的示例。

请参考以下页面了解有关模块创建方法的详细信息。

    • Developing Modules

 

    Ansible モジュール作成のイロハ | Backlogブログ

由于操作系统的不同,该模块的行为会发生变化。

首先,我将解释不是通过发行版,而是通过操作系统来改变行为的实现方式。

我们来看一下用户模块的源代码。

在这个模块中,定义了一个User类,以及它的子类FreeBsdUser类、OpenBSDUser类、NetBSDUser类、SunOS类和AIX类。

在子类中,重写了create_user()、remove_user()、modify_user()方法。

User类的new方法的定义如下:

    def __new__(cls, *args, **kwargs):
        return load_platform_subclass(User, args, kwargs)

load_platform_subclass函数的实现如下所示。

def load_platform_subclass(cls, *args, **kwargs):
    '''
    used by modules like User to have different implementations based on detected platform.  See User
    module for an example.
    '''

    this_platform = get_platform()
    distribution = get_distribution()
    subclass = None

    # get the most specific superclass for this platform
    if distribution is not None:
        for sc in cls.__subclasses__():
            if sc.distribution is not None and sc.distribution == distribution and sc.platform == this_platform:
                subclass = sc
    if subclass is None:
        for sc in cls.__subclasses__():
            if sc.platform == this_platform and sc.distribution is None:
                subclass = sc
    if subclass is None:
        subclass = cls

    return super(cls, subclass).__new__(subclass)

如果调用类具有的子类中,分布和平台匹配,则使用该子类;如果分布未定义(get_distribution 返回 None) 并且平台匹配子类存在,则使用平台匹配子类;如果不存在匹配的子类,则调用调用类的 new 方法。

其余部分是在 https://github.com/ansible/ansible/blob/v1.4.1/library/system/user#L1438 中。

    user = User(module)

通过这样的调用方式,会根据执行环境的操作系统生成相应的类实例。

根据不同的分发渠道,每个模块的行为会发生变化。

在不同的Linux发行版中,有一些模块的行为会有所不同。例如,Ansible 1.4版本新增了一个hostname模块。该模块的源代码可以在 https://github.com/ansible/ansible/blob/v1.4.1/library/system/hostname 找到。

实际上,hostname模块是我提交的合并请求所包括的。

与User类一样,Hostname类及其子类DebianHostname、UbuntuHostname、RedHat5Hostname、RedHatHostname、CentOSHostname、FedoraHostname、OpenSUSEHostname、ArchHostname被定义。

然而,由于像Debian和Ubuntu这样的发行版存在相同的主机名配置方法,因此我想进行通用化的实施。

在传统的继承基础思维中,我们希望在Hostname的子类中创建Debian和Ubuntu的共用类。但是,load_platform_subclass的实现如上引述的那样,它只会查找直接下级的子类,而不是后代类,并且需要将子类分为不同的发行版以便与get_distribution()方法的返回值进行比较。

因此,我决定将主机名设置方法放在另一个类中处理。已经定义了未实现策略、通用策略、Debian策略、RedHat策略和Fedora策略。

这些类可以在以下链接中找到:
https://github.com/ansible/ansible/blob/v1.4.1/library/system/hostname#L170-L178

class DebianHostname(Hostname):
    platform = 'Linux'
    distribution = 'Debian'
    strategy_class = DebianStrategy

class UbuntuHostname(Hostname):
    platform = 'Linux'
    distribution = 'Ubuntu'
    strategy_class = DebianStrategy

在主机名类的实现中,设置了每个子类使用的内容,可以在以下链接中找到详细信息:https://github.com/ansible/ansible/blob/v1.4.1/library/system/hostname#L90-L100。

    def get_current_hostname(self):
        return self.strategy.get_current_hostname()

    def set_current_hostname(self, name):
        self.strategy.set_current_hostname(name)

    def get_permanent_hostname(self):
        return self.strategy.get_permanent_hostname()

    def set_permanent_hostname(self, name):
        self.strategy.set_permanent_hostname(name)

通过调用的方式进行实现切换。

如果你创建了一个通用模块,可以发送一个拉取请求。

Ansible 不仅使用 Python 编写,还继承了 Python 中“内置电池”的思想。

Ansible遵循“电池包含”哲学,所以在核心分发中你有很多用于各种IT任务的优秀模块。

因此,我们很乐意采纳通用模块。

2014年05月24日添加说明 更新网站后,上述描述已经被删除。关于Batteries Included的内容可以在《Ansible配置管理指南》的最后一部分找到。

Ansible核心发行版提供近200个功能模块,为构建自动化提供了很好的基础。从服务和数据库到云服务提供商,使用Ansible您无需从头开始。

根据 https://github.com/ansible/ansible/blob/devel/CONTRIBUTING.md#sharing-a-feature-idea 和 https://github.com/ansible/ansible/blob/devel/CONTRIBUTING.md#contributing-code-features-or-bugfixes,建议使用GitHub创建一个问题(ticket)或通过邮件列表或IRC进行讨论,然后发送一个Pull Request(PR)以便对代码进行审查。

创建hostname模块时,也在邮件列表中向Michael DeHaan先生询问意见。
https://groups.google.com/d/msg/ansible-project/komqS4WdqHU/cRfWiMnCR3cJ

希望对此进行审核的正确方法是向GitHub项目提交一个拉取请求。

根据建议,我提交了一个Pull请求。一开始只支持Debian、Ubuntu、RHEL6和CentOS等几个发行版,但是在接收到其他发行版的运行报告后,支持的发行版逐渐增加。

只要接受评审并不断改进,即使最初有些不完美,也能够得到采纳。

如果大家也制作了通用模块,请务必发送拉取请求!

广告
将在 10 秒后关闭
bannerAds