使用人偶开发套件为人偶开发模块

大约一个月前,我有一个选择:是将用于puppet的模块“写到表中”(即用于内部基础结构)还是使其具有通用性,请打开源并将其发布在puppet forge上 。 当然,为自己快速绘制2-3个等级并冷静下来会更快,更轻松,但是在模块发布期间获得的经验很有价值,我想分享一下。 在RuNet中,没有有关使用up开发工具包(以下简称PDK )的信息,因此您可以考虑将其视为一种教程。


这篇文章是关于什么的


在开发模块(或两个模块)的过程中,我发现了PDK,它极大地促进了模块的开发和维护。 即:


  • 最后更新时自动格式化metadata.json
  • 可以执行以下操作的各种CI系统的配置生成:
    • 使用rubocop linter检查ruby代码
    • 运行单元测试
    • 在某些情况下-自动填写人偶伪造工作代码
  • 使用码在注释中生成基于标签的文档
  • 木偶锻件上的模块板[PDK] 。 小事,但很好!

全部感兴趣 我要一只猫!


举个例子


如果您想在阅读过程中观察和感觉到什么,可以打开提到的两个模块之一(或两个): clickhousexmlsimple 。 两者都是使用PDK和本文中描述的其他工具开发的。


目录内容



什么是PDK


根据官方文档:


创建一个包含类,定义的类型和任务的完整模块,并在进行过程中测试和验证您的工作。 PDK提供了完整的模块结构,类模板,定义的类型和任务以及测试基础结构。 您可以针对各种操作系统和多个Puppet版本验证和测试模块。

在我的免费翻译中:


允许您创建具有类,类型,任务和测试的完整模块,以验证模块的操作。 PDK为上述所有内容提供了完整的结构和模板。 使用此工具,可以检查各种版本的puppet以及不同操作系统中模块的运行情况。

听起来不错吗? 好吧,这就是事实。 直到开始研究该模块(决定立即为开放源代码编写)的那一刻,我才开始怀疑这个工具,现在我打算转移整个内部基础结构以使用PDK。


我将描述如何放置它,以及包含的工具和命令。


安装方式


官方安装页面 。 使用此链接,几乎可以保证您找到在主机上安装PDK的正确方法。 如果由于某种原因您不走运,并且您的操作系统不存在,则始终存在一个环形交叉口:


 gem install pdk 

实际上,PDK只是一个宝石,它就是这样设置的。


PDK内容


通常,PDK只是一组促进模块开发的宝石。 它包含以下工具:


效用内容描述
元数据json-lint检查metadata.json是否有匹配的木偶样式指南
通过命令行生成和测试模块及其内容(类,类型等)的工具
木偶绒检查人偶代码中的人偶语言样式指南
木偶语法验证清单的语法
puppetlabs_spec_helper提供Rake类,方法和任务,用于人偶代码的规范测试
木偶在将清单编译到资源目录(?)时测试p行为
rspec-puppet-facts允许您使用用户指定的事实来运行rspec-puppet

创建一个模块


已安装PDK,现在就可以玩了。 最简单的pdk help命令pdk help显示可用命令。 假设我们位于您拥有所有其他模块的文件夹中。 然后让我们创建一个新的:


 $ pdk new module --template-url=https://github.com/puppetlabs/pdk-templates.git *** We need to create the metadata.json file for this module, so we're going to ask you 5 questions. *** [Q 1/5] If you have a name for your module, add it here. --> dummy [Q 2/5] If you have a Puppet Forge username, add it here. --> felixoid [Q 3/5] Who wrote this module? --> Mikhail f. Shiryaev [Q 4/5] What license does this module code fall under? --> MIT [Q 5/5] What operating systems does this module support? --> RedHat based Linux, Debian based Linux, Windows Metadata will be generated based on this information, continue? Yes pdk (INFO): Module 'dummy' generated at path '/tmp/dummy', from template 'https://github.com/puppetlabs/pdk-templates.git'. 

该实用程序会问一些问题以填写metadata.json文件,并且输出的内容与所显示的完全一样:从git模板编译的模块和辅助文件。


简短说明-要素经常更改,包括一些最近已修复的严重错误。 因此,最好不要使用已安装的PDK中的默认值,而应使用最新版本。 没错,这是有--template-url :当使用--template-url参数时,PDK将此参数添加到~.pdk/cache/answers.json并根据进一步执行任何pdk命令的延迟判断,它尝试下载它们。 因此,请从answers.json删除此参数,或者在创建模块时不要使用它,并在metadata.json对其进行更改。


让我们看一下可以使用PDK执行的其他步骤。


新班


 $ pdk new class dummy::class pdk (INFO): Creating '/tmp/dummy/manifests/class.pp' from template. pdk (INFO): Creating '/tmp/dummy/spec/classes/class_spec.rb' from template. $ cat manifests/class.pp # A description of what this class does # # @summary A short summary of the purpose of this class # # @example # include dummy::class class dummy::class { } $ cat spec/classes/class_spec.rb require 'spec_helper' describe 'dummy::class' do on_supported_os.each do |os, os_facts| context "on #{os}" do let(:facts) { os_facts } it { is_expected.to compile } end end end 

此命令创建2个文件:类的清单本身和用于测试的规范文件。 稍后,我将详细介绍用于文档的标签。


新的defined_type


 $ pdk new defined_type type pdk (INFO): Creating '/tmp/dummy/manifests/type.pp' from template. pdk (INFO): Creating '/tmp/dummy/spec/defines/type_spec.rb' from template. 

都一样:资源类型和规范文件的清单。


新提供者和任务


PDK也可以创建一个新的提供程序或任务,但是我没有与他们紧密合作,因此,老实说,最好在必要时更深入地研究该主题。


用p字符串生成文档


我真的不明白为什么puppet strings不属于PDK工具包的一部分,但这只是一个事实。 如果在开发过程中正确放置了院子的标签 ,那么有两种主要方法可以为用户提供文档:


  • 将其生成为HTML / Markdown / JSON,并将其放在代码旁边。 这是通过使用puppet string generate [--format FORMAT]命令完成的,该格式可以省略,也可以设置为json / markdown
    • 通常,将存储库根目录中的REFERENCE.md文件作为文档标准,该文件标准由puppet strings generate --format markdown
  • 使用代码(假设它在github上)发布到存储库github-pages。 这很简单,您需要3个命令:
     #  Gemfile.lock,    PDK rm -f Gemfile.lock #     Gemfile   bundle bundle install --path vendor/bundle #   gh-pages   rake-task bundle exec rake strings:gh_pages:update 

似乎没有什么魔术,但是在输出处,我们有一个带有指令的模块。 优点是,即使不使用@param标记描述每个参数,输出仍将是类/类型/函数,并带有对类型和默认值的最小描述。 以我的愚见,即使这总比没有好,而且会使模块的使用更具吸引力。


当然,所有这些都可以自动化并作为CI阶段添加。 那将是完美的。 我的手还没有伸手,但积压的灰尘正在积.。 如果突然有人在这个话题上有话要说-我将不胜感激。 思路:至少添加一个检查,查看运行木偶字符串后REFERENCE.md是否更改。 如果是这样,请考虑测试失败。


模板定制


模板的文档位于pdk-templates存储库中。 简而言之,所有内容都使用模块根目录中的.sync.yml文件进行配置,而更改则使用pdk update命令应用。 该文件的每个参数都是模块目录中另一个文件的名称,必须以一种或另一种方式进行更改。 每个模板的大多数参数我都必须“通过触摸”来选择,经常查看源代码-反复试验。 此处的文档有时会远远落后。 不幸的是,除了给您自己的存储库中的示例提供链接之外,几乎没有什么可说的了。


我将快速描述上例中使用.sync.yml更改的一些参数:


  • Gemfile :在不同的组中添加了两个Gemfile作为依赖项:开发组中的pdk; 依赖组中的xml-simple。 开始测试时,未安装system_tests组,因此我将依赖项添加到另一个组。
  • spec/spec_helper.rb :更改了修改方法,已添加了最小测试覆盖率阈值,在该阈值以下,测试被视为失败。
  • .travis.yml :此文件已被抛光很长时间,因为它用于检查代码库并将完成的模块加载到puppet-forge上。 变化:
    • 用于在puppet-forge上填充模块的用户名和加密密码。 您可以在此处阅读有关使用Travis部署puppet-forge的更多信息。
    • 创建了一系列测试→部署,只有在成功进行测试的情况下才启动后者。
    • 添加了将模块部署到puppet-forge的阶段,条件是从标记中以字符“ v”开头的CI启动CI。
  • Rakefile :为Rakefile添加了一些例外。

运行各种CI


这里的一切都很简单。 使用PDK生成模块后,立即在appveyor,travis和gitlab-ci中开始验证。 要运行测试,一切.sync.yml准备就绪, .sync.yml相同的.sync.yml进行调整。 我没有特别的偏好,因此我不会推荐任何东西。 只需使用更方便的方式即可。


奖励:我们为类,类型和函数编写单元测试


这一点超出了我计划描述的基本材料,但是对我来说似乎非常有用。


因此,我们有一个带有清单的模块和一个库,该库又包含类,类型和函数(我们也不会忘记任务和提供者,但我在这一部分没有任何专业知识)。 由于存在任何出于更改目的的代码,所以很显然,将其与测试覆盖起来以确保两件事是很不错的:


  • 更改不会破坏当前行为(或测试更改行为)
  • 您的清单完全符合您的期望,并使用所有期望的资源。

Puppetlabs提供了rspec框架的扩展,称为puppet-rspec 。 链接到有关测试类型功能的文档。 不要太懒,不能仔细观察,还有其他章节。


开始使用它非常简单,甚至都不知道红宝石。 如上所示,如果使用pdk new <thing>创建了类或类型,则*_spec.rb文件也已存在。 因此,假设我们有一个dummy::class 。 要对其进行测试,必须创建具有以下内容的spec/classes/class_spec.rb文件:


 require 'spec_helper' describe 'dummy::class' do on_supported_os.each do |os, os_facts| context "on #{os}" do let(:facts) { os_facts } it { is_expected.to compile } end end end 

您可以通过从模块的根目录运行pdk test unit来进行验证。


这几乎是我们所需要的。 现在剩下class_spec.rb是用适当的条件class_spec.rb必要的is_expected来补充class_spec.rb 。 例如,要检查该类是否包含具有某些参数的file {'/file/path': }资源,可以执行以下操作:


 it do is_expected.to contain_file('/file/path').with( 'ensure' => 'file', 'mode' => '0644' ) end 

您可以使用let(:params) { {'param1' => 'value'} }来设置类参数,可以通过将每个参数放在context 'some description' {}的选定部分中来在各种输入条件下进行测试。 可以检查资源之间以及类之间的依赖关系:例如,如果假设类声明包含inherits ,则可以将is_expected.to contain_class('parent_class_name')添加到is_expected.to contain_class('parent_class_name') 。 需要检查不同操作系统的行为吗? 这也是可能的:我们仅在单独的上下文中指出必要的事实:


 context 'with Debian' do let(:facts) do { os: { architecture: 'amd64', distro: { codename: 'stretch', id: 'Debian', release: { full: '9.6', major: '9', minor: '6', }, }, family: 'Debian', name: 'Debian', release: { full: '9.6', major: '9', minor: '6', }, selinux: { enabled: false, }, }, osfamily: 'Debian', } end it { is_expected.to something } end 

通常,就我在编写测试过程中注意到的而言,该框架使您可以检查几乎所有需要的东西。 当某些参数从子类移到模块的顶级类时,测试的存在曾经帮助过我:它们表明重构不会破坏任何内容,整个模块的行为也不会改变。


代替输出


从本文的一般语气中已经可以理解,Puppet在使用模块方面的工作量大大增加了,这使我感到非常鼓舞。 常规操作是自动进行的,尽可能使用模板,开箱即用地提供流行CI的配置。 这似乎是一种开销,并且使用可能无法带来预期的效果,但是绝对值得。 如果比较如何在不使用PDK和使用PDK的情况下开发模块,那么对我来说,它看起来像这样:


没有发展 胡须 PDKPDK开发

尝试一下,为自己和您的同事简化生活。 我很乐意回答潜在的问题。


愿雾化与我们同在!

Source: https://habr.com/ru/post/zh-CN435954/


All Articles