本文将介绍puppet的语法,因为puppet是用ruby编写的,因此puppet的语法也和ruby类似,都是很简单的面对对象的高级语言。再次强调,puppet把需要管理的内容抽象成为资源,每种资源有不同的属性,因此puppet语言就是描述这些资源的属性以及资源之间关系的语言。
一、资源
定义一个资源,需要指定资源的类型和资源的title。看一个例子:
f i l e { " / etc /passwd" : name => " / etc / passd " , owner => root , group => root , mode => 644; }
上面的代码让/etc/passwd的权限保持644,并且属于root用户和root用户组,file是指定资源的类型是"file"类型,第二行的"/etc/passwd"是资源的title, title的作用是让puppet能唯一标识这个资源。第三行的name指定了要对那个文件操作,默认情况下,name都等于title,所以很多时候name是可以省略的。这点要注意。看下面的例子:
f i l e { " sshdconfig " : name => $operatingsystem ? { s o l a r i s => " / usr / l o c a l / etc / ssh / sshd_config " , default => " / etc / ssh / sshd_config " , } , owner => root , group => root , mode => 644 , }
资源的title是sshdconfig,但是name却可以通过判定操作系统自己选择合适的值。这样,当其他的资源要依赖sshdconfig的时候,只需要说明依赖sshdconfig就行,不需要关心文件到底在什么路径下面。例如下面的代码:
s e r v i c e { " sshd " : subscribe => F i l e [ sshdconfig ] , }
指定了一个sshd的服务,这个服务如果发现文件资源sshdconfig 有变动,就会自己reload配置文件。是不是很方便呢?注意上面的subscribe后面的File,第一个字母要大写,定义资源关系的时候,这里的字母要大写。
通常,在puppet代码里面可能会定义很多相同的资源,可以用[]把所有资源的title写在一起,例如:
f i l e { [ " / etc /passwd" , " / etc / hosts " ] : owner => root , group => root , mode => 644; }
你可能已经发现了,每次定义文件的时候如果都输入mode,owner,group会很繁琐,因此你可以在puppet的site.pp的开头定义资源的默认值。定义资源的默认值需要把资源的第一个资源大写。例如下面的代码让所有的file资源的mode是644,owner是root。
F i l e { owner => root , mode => 644 ; }
默认值可以被后面的设置覆盖。
在puppet里面可以定义资源之间的关系,例如前面提到的,如果sshdconfig文件如果有修改,sshd服务就重启。puppet里面还有另一个资源关系,依赖。例如资源A依赖资源B,如果资源B不存在,资源A就不被执行。定义资源依赖的属性是requre 。例如:
f i l e { " / etc / apache2 / port . conf " : content => "80" , require => Package [ "apache2" ] ; } package { "apache2" : ensure => i n s t a l l e d ; }
file资源设置port.conf的内容为80,但是在设置file资源之前,要求apache2这个软件包配置好了。#p#
二、 类和函数
类的作用是把一组资源收集在一个盒子里面,一起使用,例如把sshd和他的配置文件做成一个ssh类,其他的地方要用到就直接包含ssh类就可以了,方便写出更简洁的代码,便于维护。类可以继承。看一个具体的例子:
c l a s s ssh { f i l e { " / etc / ssh / sshd_config " : source => "puppet : / / $ f i l e s e r v e r / ssh / sshd_config . cfg " ; } package { " ssh " : ensure => i n s t a l l e d ; } s e r v i c e { " ssh " : ensure => running ; } }
这里,file /etc/ssh/sshd_config的内容是从puppet服务器上面下载的,file资源的内容可以从别的url得到,也可以erb模板生成,erb模板是很强大的工具,这个后面会说到。package资源安装ssh软件,service资源保证ssh服务在运行状态。类的继承这里就不讲了,因为是入门手册,另外用的不多。
puppet的官方文档里面是没有puppet函数这一说法的,而是叫做define ; 这里我写做函数,是因为define实现的功能其实和函数一样,而且在ruby里面也是用define来定义一个函数。这里写做函数,便于理解。
具体来看一个例子:
define svn_repo ( $path ) { exec { " / usr / bin /svnadmin? create ?$path / $ t i t l e " : unless => " / bin / t e s t ???d?$path " , } } svn_repo { puppet_repo : path => " / var / svn_puppet " } svn_repo { other_repo : path => " / var / svn_other " }
首先用define定义了一个svn_repo函数,并且带了一个参数1 。这个参数可以在函数里面的资源使用,在这里,exec资源根据提供的参数创建svn 仓库。函数定义好以后,后面的两行就用定义好的函数创建了两个svn库。#p#
三、 节点
puppet如何区分不同的客户端,并且给不同的服务端分配manifest呢?puppet使用叫做node的语法来做这个事情,node 后面跟客户端的主机名3,例如下面的例子:
node ' host1 . example . com ' { include ssh } node ' host2 . example . com ' { include apache , mysql , php }
当主机host1.example.com来连服务端时,只会执行node 'host1.example.com'里面的代码,不会执行node host2.example.com里面的代码。正如前面所说,可以定义一个default结点。比如没有针对host3的node配置,host3就用default的配置了。在这里include的意思是include 类。同样,节点也支持继承,同样,也不打算深入。
使用节点的时候,尽量把所有的配置写成类,节点里面定义好变量和包含相应的类就可以了。保证代码的简洁。例如:
1、因为可以带参数,所以我觉得翻译成函数更好
2、注意看函数的使用语法,是不是和使用资源一样,path可以看作是属性
3、主机名在puppet里面很重要
node ' host4 . example . com ' { $networktype=" t e l e " $nagioscheckport=" 80 ,22 ,3306 " include ssh , apache , mysql }
#p#
四、变量和数组
puppet也和其他语言一样,支持变量和数组,puppet用$符号定义变量,变量的内容用双引号括起来。例如:
$test=" hello , guys " f i l e { " /tmp/ t e s t " : content => $test ; }
puppet可以使用由facter提交的变量,facter在客户端收集系统信息整理成不同的变量提交给puppet服务器端,服务器端的代码可以使用这些变量实现高级的功能,例如不同的硬件配置生成不同的应用软件配置文件。运行facter命令可以看到很多变量的输出,这些变量可以在puppet代码里面直接使用。
puppet利用方括号来定义数组,数组的内容由逗号分割,例如下面的例子:
[ "apache2" , " httpd " , " ssh " ]
数组可以用在资源定义里面,例如前面提到的例子。也可以用在函数里面,例如:
define php : : pear ( ) { package { " `php??$ {name} " : ensure => i n s t a l l e d } } php : : pear { [ ' ldap ' , ' mysql ' , ' ps ' , 'snmp ' , ' s q l i t e ' , ' t i d y ' , ' xmlrpc ' ] : }
变量也有有效范围,同其他语言一样分为局部和全局变量,简单说来,就是在里面定义的变量的使用范围就限制在里面。同时,puppet还简单的支持if ... eles 语法,但是用的不多,不在深入。
#p#
五、 模块
简单来说,一个模块就是一个/etc/puppet/modues目录下面的一个目录和它的子目录,在puppet的主文件site.pp里面用import modulename可以插入模块。新版本的puppet可以自动插入/etc/puppet/modues目录下的模块。引入模块,可以结构化代码,便于分享和管理。例如关于apache的所有配置都写到apache模块下面。一个模块目录下面通常包括三个目录,files, manifests,templates 。manifests 里面必须要包括一个init.pp的文件,这是该模块的初始文件,导入一个模块的时候,会从init.pp开始执行。可以把所有的代码都写到init.pp里面,也可以分成多个pp文件,init 再去包含其他文件。
files目录是该模块的文件发布目录,puppet提供一个文件分发机制,类似rsync的模块。templates 目录包含erb模型文件,这个和file资源的template属性有关。
puppet安装好以后,modules目录是没有的,自己建立一个就行,然后在里面可以新增加你的模块。请养成使用模块的习惯。
【编辑推荐】
【责任编辑:李晶 TEL:(010)68476606】