William's Blog with Octopress

Octopress is A blogging framework for hackers.

Chef基础之LWRP

| Comments

概述

Chef内置的Resources和Providers已经非常强大了,如果有些需求还不能满足,或者用内置的比较麻烦,这时可以编写自己的Resources和Providers

如果你看到别人的cookbook里有带有下画线的Resource,例如下面这个:

1
2
3
4
5
apt_repository "zenoss" do
  uri "http://dev.zenoss.org/deb"
  components ["main","stable"]
  action :add
end

那么它有可能就是一个一个Lightweight Resource.这里之所以说可能是因为还有其它的一些东西也是这种格式(以后会介绍到)

这个文档我们来看一下怎么写LWRP,主要是基本官方的Wiki,如果英文够好,可以直接看官方的,地址是: Lightweight Resources and Providers

在介绍LWRP之前我们先来回顾一下什么是Resource和Provider.简单来说Resource就是以一种抽象的方式来描述系统的某一部分我希望它处在一种什么状态, 如下面的例子

1
2
3
4
package "vim" do
  version "1.16.1-1"
  action :install
end

这条Resource就是描述说我希望我的系统中版本为1.16.1-1的vim这个包处于安装的状态,Resource会有一些属性(这里是version),对这个状态做自定.还会有一个动作,通过这个动作将系统的某一部分改变到我们希望的状态.

那么什么是Providers呢,看上面的例子,如果我们把它用bash命令来表示,它可能会是yum -y install vimapt-get install vim.我们之所以可以用上面那种抽象的方式来表达我的需求,而不用关心底层它是怎么做到的,就是因为有Provider为我们做这个工作.Provider为我们提供了这一层的抽象

文件位置

轻量级(或叫自定义)Resources和Providers分区从cookbook的resourcesproviders目录加载.Resources和Providers的名字由cookbook的名字与文件的名字通过下画线组合而成.唯一的例外是文件名为default.rb.在这种情况下Resources和Providers的名字仅是cookbook的名字

例子

Note: 下面的例子只是为了说明名字,不一定真的有这些LWRP

1
2
3
4
5
6
7
8
9
10
11
+----------------------------------------------------------------------------------------+-------------------------------------+
| Filename                               | Resource or Provider Name, as used in the DSL | Generated Class                     |
+----------+-----------------------------+-----------------------------------------------+-------------------------------------+
| /cookbooks/aws/resources/default.rb    | aws                                           | Chef::Resource::Aws                 |
+----------------------------------------+-----------------------------------------------+-------------------------------------+
| /cookbooks/aws/resources/elastic_ip.rb | aws_elastic_ip                                | Chef::Resourcesce::AwsElasticIp     |
+----------------------------------------+-----------------------------------------------+-------------------------------------+
| /cookbooks/aws/providers/default.rb    | aws                                           | Chef::Providerser::Aws              |
+----------------------------------------+-----------------------------------------------+-------------------------------------+
| /cookbooks/aws/providers/elastic_ip.rb | aws_elastic_ip                                | Chef::Providerrovider::AwsElasticIp |
+----------------------------------------+-----------------------------------------------+-------------------------------------+

Resources

前面已经说过,Resources会有一个或多个属性,我们在写Recipe的时候会给属性一些我们想要的值,这些值可以通过属性传给Provider.Resources还会有一个动作,这个动作具体做什么是在Providers中定义的

Providers

Providers就是支持Resources的,它可以通过实例变量@new_resource做为载体来来得到我们在Recipes中传给Resources的属性在值,定义Resource中的动作具体做些什么动作.完了之后调用`@new_resource.updated_by_last_action(true)来告诉Chef我们做完了

下面我们以一个简单的例子来加深一下理解,主要注意里面变量(属性)的传递

简单的例子

这个例子我们简单的封装一个内容Resource类型user得到一个LWRP

首先我们利用knife命令创建cookbook的目录结构

knife cookbook create users

然后我们直接在resources目录下创建我们的resource

vim users/resources/manage.rb
1
2
3
actions :create, :remove

attribute :user_name, :kind_of => String, :required => true

我们定义了两个动作和一个属性,这两个具体做什么工作是在Provider中实现的,在recipe使用这个Resource的时候传来属性的值可以在Provider中访问到

下面我们创建我们的Provider用来支持Resource.实现上就是定义前面的两个动作要做什么工作

vim users/providers/manage.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
action :remove do
  user new_resource.user_name do
    action :remove
  end
  new_resource.updated_by_last_action(true)
end

action :create do
  user new_resource.user_name do
    action :create
  end
  new_resource.updated_by_last_action(true)
end

我们定义了两个动作,使用内置的Resource类型user来创建用户,利用new_resource得到从recipes中传来的用户名,最后更新状态

下面我们就在这个cookbook中使用我们定义的Resource.Cookbook的名字为users,Resouces文件的名字为manage.rb,所以我们的Resource名字为users_manage

vim users/recipes/test.rb
1
2
3
users_maange "william" do
  user_name "william"
end

现在就可以测试我们写的LWRP了

knife cookbook upload users
knife node run list add client1.chef.com 'recipe[users::test]'

Comments