跳转至

第七节 属性

  • Motd-Attributes菜谱
  • Setting Attributes
  • 属性优先级基础
  • Include_Recipe
  • 属性优先级
  • 属性排错

1、Chef 属性

属性代表的是你的节点的相关信息。除了ohai自收集的节点相关信息之外, 你还可以在chef配方单或额外的属性文件中设定属性

属性文件在菜谱的attributes此目录中。和配方单类似, 莫认属性文件叫default.rb

<cookbook>
└── attributes
    └── default.rb

使用菜谱中的属性文件来设定的属性的格式。

Alt Image Text

属性也可以在配方单中设定,展示在配方单中所设定的属性的格式口在配方单中设定属性时必须使用node.前缀

Alt Image Text

Because attributes can be defined in multiple places, all attribute values are composed together during a Chef run according to the priority levels as shown in Figure

Attributes defined by ohai have the highest priority, followed by attributes defined in a recipe, then attributes defined in an attribute file.

In other words, recipe attributes have a higher priority than those defined in attribute file, and will override them by default. Attributes defined by ohai trump everything else.

Alt Image Text

ohai > attributes defined in a recipe > attributes defined in an attribute file

2、Motd-Attributes菜谱

我们用一个叫・Motd-Attributes的菜谱来试验菜谱中的属性,这里来写一个由属胜驱动的版本 。

首先,使用chef generate cookbookknife cookbook create(取决于开发机器使用Chef开发包还是客户端)来生成motd-attributes菜谱的目录结构。

Chef开发包

$ chef generate cookbook motd-attributes
 chef generate cookbook motd-attributes
Hyphens are discouraged in cookbook names as they may cause problems with custom resources. See https://docs.chef.io/ctl_chef.html#chef-generate-cookbook for more information.
Generating cookbook motd-attributes
- Ensuring correct cookbook content
- Committing cookbook files to git

Your cookbook is ready. Type `cd motd-attributes` to enter it.

There are several commands you can run to get started locally developing and testing your cookbook.
Type `delivery local --help` to see a full list of local testing commands.

Why not start by writing an InSpec test? Tests for the default recipe are stored at:

test/integration/default/default_test.rb

If you'd prefer to dive right in, the default recipe can be found at:

recipes/default.rb



$ cd motd-attributes

Chef客户端

$ knife cookbook create motd-attributes --cookbook-path .
$ cd motd-attributes
$ kitchen init --create-gemfile
$ bundle install

/motd-attributes/kitchen.yml

---
driver:
  name: vagrant
  provider: vmware_desktop

provisioner:
  name: chef_zero

platforms:
  - name: centos65
    driver:
      box: learningchef/centos65
      box_url: learningchef/centos65

suites:
  - name: default
    run_list:
      - recipe[motd-attributes::default]
    attributes:

创建一个配方单使用template资源来生成节点上的/etc/motd文件。但这一次,使用模板文件中的属胜。

motd-attributes/recipes/default.rb

#
# Cookbook:: motd-attributes
# Recipe:: default
#
# Copyright:: 2019, The Authors, All Rights Reserved.

template '/etc/motd' do
    source 'motd.erb'
    mode '0644'
end

Generate a template file to generate /etc/motd.

Chef开发包

$ chef generate template motd
Recipe: code_generator::template
  * directory[/Users/.../Devops_sap/Chef_Doc/learningchef/chap08/motd-attributes/templates] action create
    - create new directory /Users/.../Devops_sap/Chef_Doc/learningchef/chap08/motd-attributes/templates
  * template[/Users/.../Devops_sap/Chef_Doc/learningchef/chap08/motd-attributes/templates/motd.erb] action create
    - create new file /Users/.../Devops_sap/Chef_Doc/learningchef/chap08/motd-attributes/templates/motd.erb
    - update content in file /Users/.../Devops_sap/Chef_Doc/learningchef/chap08/motd-attributes/templates/motd.erb from none to e3b0c4
    (diff output suppressed by config)

Chef Client - Linux/Mac OS X:

$ touch templates/default/motd.erb

templates/default/motd.erb

The hostname of this node is <%= node['hostname'] %>
The IP address of this node is <%= node['ipaddress'] %>
$ kitchen list
Instance          Driver   Provisioner  Verifier  Transport  Last Action    Last Error
default-centos65  Vagrant  ChefZero     Busser    Ssh        <Not Created>  <None>


$ kitchen converge

$ kitchen login
Last login: Thu Nov 28 03:12:17 2019 from 172.16.72.2
The hostname of this node is default-centos65
The IP address of this node is 172.16.72.142

$ exit

3、Setting Attributes

Chef Development Kit:

$ chef generate attribute default


Recipe: code_generator::attribute
  * directory[/Users/.../Devops_sap/Chef_Doc/learningchef/chap08/motd-attributes/attributes] action create
    - create new directory /Users/.../Devops_sap/Chef_Doc/learningchef/chap08/motd-attributes/attributes
  * template[/Users/.../Devops_sap/Chef_Doc/learningchef/chap08/motd-attributes/attributes/default.rb] action create
    - create new file /Users/.../Devops_sap/Chef_Doc/learningchef/chap08/motd-attributes/attributes/default.rb
    - update content in file /Users/.../Devops_sap/Chef_Doc/learningchef/chap08/motd-attributes/attributes/default.rb from none to e3b0c4
    (diff output suppressed by config)

Chef Client - Linux/Mac OS X:

$ touch attributes/default.rb

默认情况下,如果使用Chef开发包生成新菜谱的目录结构,它不会创建attribute目录,因为你不一定会用到它。然而,在需要在菜谱中使用属性文件时,你需要运行chef generate命令来创建其目录结构。

而如果使用Chef客户端创建新菜谱的目录结构,它永远会创建所有的目录(包括attribute、目录,无论你是否需要),但你需要自己手动创建default.rb属性文件。

/attributes/default.rb

default['motd-attributes']['company'] = 'Chef'

根据约定,在菜谱的属性文件中设定属性时,属性的键和值应该存在以菜谱名字命名的顶级命名空间下。

比如default['motd-attributes']['company']的值是字符串Chef,键company存在顶级命名空间motd-attributes下。

在这个例子中,菜谱的名字在metadata.rb中定义为mot-attributes这个属性使用default优先级。

/recipes/default.rb

node.default['motd-attributes']['message'] = "It's a wonderful day today!"

template '/etc/motd' do
  source 'motd.erb'
  mode '0644'
end

编辑mold.erb模板。可以在node对象下访问通过任何途径设定的属胜属性文件菜谱或ohai

templates/default/motd.erb

Welcome to <%= node['motd-attributes']['company'] %>
<%= node['motd-attributes']['message'] %>
The hostname of this node is <%= node['hostname'] %>
The IP address of this node is <%= node['ipaddress'] %>
$ kitchen converge
-----> Starting Kitchen (v2.3.3)
-----> Converging <default-centos65>...
       Preparing files for transfer
$$$$$$ You must set your run_list in your Policyfile instead of kitchen config. The run_list in your config will be ignored.
$$$$$$ Ignored run_list: ["recipe[motd-attributes::default]"]
       Installing cookbooks for Policyfile /Users/.../Devops_sap/Chef_Doc/learningchef/chap08/motd-attributes/Policyfile.rb using `chef in
stall`
       Installing cookbooks from lock
       Installing motd-attributes 0.1.0
       Preparing dna.json
       Exporting cookbook dependencies from Policyfile /var/folders/r7/nml_dsbn44gcd2jlqh7s2w940000gn/T/default-centos65-sandbox-20191129-2695
5-1g48hf7...
       Exported policy 'motd-attributes' to /var/folders/r7/nml_dsbn44gcd2jlqh7s2w940000gn/T/default-centos65-sandbox-20191129-26955-1g48hf7

       To converge this system with the exported policy, run:
         cd /var/folders/r7/nml_dsbn44gcd2jlqh7s2w940000gn/T/default-centos65-sandbox-20191129-26955-1g48hf7
         chef-client -z
       Removing non-cookbook files before transfer
       Preparing validation.pem
       Preparing client.rb
-----> Chef installation detected (install only if missing)
       Transferring files to <default-centos65>
       Starting Chef Infra Client, version 15.5.17
       Using policy 'motd-attributes' at revision '3e7401637721e60a1aa8475f5dd46efd6ad452ec2cb08118d94bbf112815ab5e'
       resolving cookbooks for run list: ["motd-attributes::default@0.1.0 (4b1d2ce)"]
       Synchronizing Cookbooks:
         - motd-attributes (0.1.0)
       Installing Cookbook Gems:
       Compiling Cookbooks...
       Converging 1 resources
       Recipe: motd-attributes::default
         * template[/etc/motd] action create
           - update content in file /etc/motd from 0397e6 to b17ece
           --- /etc/motd        2019-11-28 03:12:20.412305997 +0000
           +++ /etc/.chef-motd20191129-3585-p6oosp      2019-11-29 02:24:14.925471024 +0000
           @@ -1,3 +1,8 @@
           +# The hostname of this node is default-centos65
           +# The IP address of this node is 172.16.72.142
           +
           +Welcome to Chef
           +It's a wonderful day today!
            The hostname of this node is default-centos65
            The IP address of this node is 172.16.72.142

       Running handlers:
       Running handlers complete
       Chef Infra Client finished, 1/1 resources updated in 01 seconds
       Downloading files from <default-centos65>
       Finished converging <default-centos65> (0m8.64s).
-----> Kitchen is finished. (0m9.31s
$ kitchen login
Last login: Fri Nov 29 02:24:10 2019 from 172.16.72.2
# The hostname of this node is default-centos65
# The IP address of this node is 172.16.72.142

Welcome to Chef
It's a wonderful day today!
The hostname of this node is default-centos65
The IP address of this node is 172.16.72.142

[vagrant@default-centos65 ~]$ exit
logout
Connection to 127.0.0.1 closed.

4、属性优先级基础

现在, 让我们来试验一下不同属性的优先级。 重新设定已经在其他地方设定过的属性值 编辑recipe/default.rb, 重设一个在属文件中已经由ohai设定的更高优先级的属性的值,同时重设一个在属性文件中已经设定的更低优先级的属性的值

motd-attributes/recipes/default.rb

#
# Cookbook:: motd-attributes
# Recipe:: default
#
# Copyright:: 2019, The Authors, All Rights Reserved.

node.default['ipaddress'] = '1.1.1.1'
node.default['motd-attributes']['company'] = 'My Company'
node.default['motd-attributes']['message'] = "It's a wonderful day today!"

template '/etc/motd' do
  source 'motd.erb'
  mode "0644"
end
$ kitchen converge

$ kitchen login

Last login: Fri Nov 29 03:09:32 2019 from 172.16.72.2
Welcome to My Company
It's a wonderful day today!
The hostname of this node is default-centos65
The IP address of this node is 172.16.72.142

Perform a Chef run and check to see the resulting values:

  • 在配方单中设定的mode['motd_attributes']['company']的值My Company比属性文件中设定的值Chef拥有更高优先级,因此模板使用了配方单中设定的值。
  • 在配方单中设定的node['ipaddeess']值比ohai自动设定的10.0.2.15值有更低优先 级,因此在配方单中设定的值被忽略,模板使用了高优先级的值。

  • 这些优先级体现了变量的使用方法在属胜文件中设定的值被设计为可以被配方单覆盖

  • 而由ohai生成的自动属胜则不会被任何属性覆盖,因为它们代表重要的不应被篡改的系统信息,比如IP地址。

5、Include_Recipe

你可能会想Chef这样的属性优先级机制有没有必要这是因为和很多其他编程语言一样,Chef配方单可以通过include_recipe语句引用其他Chef配方单。

Chef运行并处理Chef代码时,它可能包含对许多不同的配方单(甚至在其他菜谱中的配方单)的引用.

由于你可以使用include_recipe,所以Chef代码可能会包含互相冲突的属性定义,这样便需要一个准则来决定相冲突的属性在定义时,哪个会胜出。

Alt Image Text

说明:很多Chef用户遵循一个准则,将配方单代码的长度限制在一个屏幕能显示出来的范围内 > (20多行)以使代码可读。更长的代码通常可以考虑根据代码块的用途分割成多个不同的配方单> 文件,然后使用include_ recip来包含这些配方单

在使用include_recipe语句时,你应该使用和在运行清草中一样的格式:"<菜谱>::<配方单>"。比如"motd-attributes::message"

Chef开发包

chef generate recipe message

Chef Client - Linux/Mac OS X:

touch recipes/message.rb
$ chef generate recipe message
Recipe: code_generator::recipe
  * directory[/Users/.../Devops_sap/Chef_Doc/learningchef/chap08/motd-attributes/spec/unit/recipes] action create (up to date)
  * cookbook_file[/Users/.../Devops_sap/Chef_Doc/learningchef/chap08/motd-attributes/spec/spec_helper.rb] action create_if_missing (up to date)
  * template[/Users/.../Devops_sap/Chef_Doc/learningchef/chap08/motd-attributes/spec/unit/recipes/message_spec.rb] action create_if_missing
    - create new file /Users/.../Devops_sap/Chef_Doc/learningchef/chap08/motd-attributes/spec/unit/recipes/message_spec.rb
    - update content in file /Users/.../Devops_sap/Chef_Doc/learningchef/chap08/motd-attributes/spec/unit/recipes/message_spec.rb from none to 6d73b3
    (diff output suppressed by config)
  * directory[/Users/.../Devops_sap/Chef_Doc/learningchef/chap08/motd-attributes/test/integration/default] action create (up to date)
  * template[/Users/.../Devops_sap/Chef_Doc/learningchef/chap08/motd-attributes/test/integration/default/message_test.rb] action create_if_missing
    - create new file /Users/.../Devops_sap/Chef_Doc/learningchef/chap08/motd-attributes/test/integration/default/message_test.rb
    - update content in file /Users/.../Devops_sap/Chef_Doc/learningchef/chap08/motd-attributes/test/integration/default/message_test.rb from none to 456a77
    (diff output suppressed by config)
  * template[/Users/.../Devops_sap/Chef_Doc/learningchef/chap08/motd-attributes/recipes/message.rb] action create
    - create new file /Users/.../Devops_sap/Chef_Doc/learningchef/chap08/motd-attributes/recipes/message.rb
    - update content in file /Users/.../Devops_sap/Chef_Doc/learningchef/chap08/motd-attributes/recipes/message.rb from none to f414d1
    (diff output suppressed by config)

recipes/message.rb

#
# Cookbook:: motd-attributes
# Recipe:: message
#
# Copyright:: 2019, The Authors, All Rights Reserved.


node.default['motd-attributes']['company'] = 'the best company in the universe(This info from message.rb)'

提示:

注意,我们kitchen.yml文件在运行清单中仍然只使用了default配方单。因为我们不想让人们直接使用message配方单。

只是使用message配方单来组织代码,使其可读,容易管理。因此, 我们需要在default配方单中使用include_recipe来引用需要引用的配方单, 而总的运行清单中只有default配方单

...
  run_list:
    - recipe[motd-attributes::default]
...

有些Chef用户将“私有”的配方单文件以下划线开头("-“)作为一个约定来区分公开和私有的配方单文件 。他们同时将这个配方单文件命名为”message.rb“,使其私有性在菜谱的文件结构中显得更明显。

end:

node.default['ipaddress'] = '1.1.1.1'
node.default['motd-attributes']['company'] = 'My Company'
node.default['motd-attributes']['message'] = "It's a wonderful day today!"

include_recipe 'motd-attributes::message'

template '/etc/motd' do
  source 'motd.erb'
  mode '0644'
end

You need to add an include_recipe statement to your default.rb.

recipes/default.rb

#
# Cookbook:: motd-attributes
# Recipe:: default
#
# Copyright:: 2019, The Authors, All Rights Reserved.

node.default['ipaddress'] = '1.1.1.1'
node.default['motd-attributes']['company'] = 'My Company'
node.default['motd-attributes']['message'] = "It's a wonderful day today!"

include_recipe 'motd-attributes::message'

template '/etc/motd' do
  source 'motd.erb'
  mode "0644"
end

include_recipe语句可以放在配方单文件的任何位置。当Chef处理这些代码时include_recipe将被替换为它所引用用的配方单代码

Alt Image Text

同个优先级同个属性被多次设定时,最后设定的值胜出

在本例中,在include_recipe引用展开后,node.defau1t["motd-attributes"]["company"]属性被设定了两次;

template资源应用之前最后被设定的一个胜出,即“the best company in the universe(This info from message.rb)":

$ kitchen converge

$ kitchen login
Last login: Fri Nov 29 06:27:57 2019 from 172.16.72.2
Welcome to the best company in the universe(This info from message.rb)
It's a wonderful day today!
The hostname of this node is default-centos65
The IP address of this node is 172.16.72.142

6、属性优先级

三个最常用的属性优先级别:

自动(Autormatic)

自动属性为ohai所生成的属性。

默认(Default)

通常由菜谱及属性文件设定的属性。

重写(Override)

最强的属性设定方法,务必请谨慎使用。

Alt Image Text

在菜谱中设定一个属性时,通常应该设为默认属性。这个规则有一个例外,即当使用环境时使用override优先级。

除了使用“环境”的特例之外,属性优先级多自定义Chef的时候。在Chef中实现一个新的功能(比如自定义资源)时,Chef强大的属性优先级引擎能帮助你遵循本章讲述的基本属性优先级功能为其语言添加新的功能。

7、属性排错

如果需要为属性拍错,比如找到他们哪里设定,node对象提供的node.debug_value()方法能给与很多帮助。

比如如果你不知道ohai设定了自动属性node['ipaddress']得知它是由。可以通过运行node.debug_value()得知由ohai设定的

修改recipes/default.rb文件,可以使用Ruby的pp程序,pp程序可以将对象Ruby以可读性强格式打印出来。node.debug_value()返回对象的内容, pp输出有较强的可读性

#
# Cookbook:: motd-attributes
# Recipe:: default
#
# Copyright:: 2019, The Authors, All Rights Reserved.


require 'pp'
node.default['ipaddress'] = '1.1.1.1'
pp node.debug_value('ipaddress')

node.default['motd-attributes']['company'] = 'My Company'
node.default['motd-attributes']['message'] = "It's a wonderful day today!"

include_recipe 'motd-attributes::message'

template '/etc/motd' do
  source 'motd.erb'
  mode "0644"
end
$ kitchen converge
...
 Installing Cookbook Gems:
       Compiling Cookbooks...
       [["default", "1.1.1.1"],
        ["env_default", :not_present],
        ["role_default", :not_present],
        ["force_default", :not_present],
        ["normal", :not_present],
        ["override", :not_present],
        ["role_override", :not_present],
        ["env_override", :not_present],
        ["force_override", :not_present],
        ["automatic", "172.16.72.142"]]
       Converging 1 resources
       Recipe: motd-attributes::default
         * template[/etc/motd] action create (up to date)

       Running handlers:
       Running handlers complete
       Chef Infra Client finished, 0/1 resources updated in 01 seconds
       Downloading files from <default-centos65>
       Finished converging <default-centos65> (0m6.47s).

从这里, 可以看出node[ipaddress]]属性在automatic优先级被设定为"172.16.72.142",在default优先级被设定为"1.1.1.1"

Chef的确处理了"1.1.1.1"这个值,但最终结果被高优先级的自动属性覆盖。

要为同个优先级别被多次设定的属性排错比在不同优先级别设定的时候复杂一些

但仍然非常可行。你只需要在include_recipe前后分别打印node.debug_value()的值。

比如,假设我们不知道motd-attributes::message配方单设定了motd-attributes::message属性,就可以通过在recipes/default.rb一中多次打印node.debug_value() 的值,在include_recipe前后分别打印node.debug_value('motd-attributes','company')

...
  Compiling Cookbooks...
       [["default", "1.1.1.1"],
        ["env_default", :not_present],
        ["role_default", :not_present],
        ["force_default", :not_present],
        ["normal", :not_present],
        ["override", :not_present],
        ["role_override", :not_present],
        ["env_override", :not_present],
        ["force_override", :not_present],
        ["automatic", "172.16.72.142"]]
       [["default", "My Company"],
        ["env_default", :not_present],
        ["role_default", :not_present],
        ["force_default", :not_present],
        ["normal", :not_present],
        ["override", :not_present],
        ["role_override", :not_present],
        ["env_override", :not_present],
        ["force_override", :not_present],
        ["automatic", :not_present]]
       [["default", "the best company in the universe(This info from message.rb)"],
        ["env_default", :not_present],
        ["role_default", :not_present],
        ["force_default", :not_present],
        ["normal", :not_present],
        ["override", :not_present],
        ["role_override", :not_present],
        ["env_override", :not_present],
        ["force_override", :not_present],
        ["automatic", :not_present]]
       Converging 1 resources
       Recipe: motd-attributes::default
         * template[/etc/motd] action create (up to date)
...

From this output, you could sort out that something inmotd-attributes::message recipe set the attribute node['motd-attributes']['company'] to "the best company in the universe" using the default precedence, overriding what was set earlier.

$ kitchen destroy
-----> Starting Kitchen (v2.3.3)
-----> Destroying <default-centos65>...
       ==> vagrant: A new version of Vagrant is available: 2.2.6 (installed version: 2.2.5)!
       ==> vagrant: To upgrade visit: https://www.vagrantup.com/downloads.html

       ==> default: Stopping the VMware VM...
       ==> default: Deleting the VM...
       Vagrant instance <default-centos65> destroyed.
       Finished destroying <default-centos65> (0m23.58s).
-----> Kitchen is finished. (0m24.15s)

8、小结

属性可以在多处设定

  • ohai自动设定
  • 属性文件
  • 配方单
  • 其他菜谱

由于属性可以在多处设定,所以Chef定义了优先级方案来控制多处设定属性如何调用设定属性时,automatic,defaultoverride来控制属性的优先级。 总的来说,会用到default优先级,除非有特别需求或需要自定义Chef.

  • Chef开发包
$ chef generate cookbook motd-attributes
  • Chef客户端
$ knife cookbook create motd-attributes --cookbook-path .
$ cd motd-attributes
$ kitchen init --create-gemfile
$ bundle install
$ kitchen list

$ kitchen converge

$ kitchen login
$ chef generate attribute default #chef-dk
$ touch attributes/default.rb  #chef-client

$ chef generate recipe message  #chef-dk
$ touch recipes/message.rb  #chef-client

Chef开发包

chef generate recipe message