磨刀不误砍柴工 Puppet语法详解

运维 系统运维
puppet把需要管理的内容抽象成为资源,每种资源有不同的属性,因此puppet语言就是描述这些资源的属性以及资源之间关系的语言。本文将详细介绍开源自动化配置管理工具puppet的语法。

本文将介绍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目录是没有的,自己建立一个就行,然后在里面可以新增加你的模块。请养成使用模块的习惯。

【编辑推荐】

  1. 开源自动化配置管理工具Puppet入门教程
  2. SVN自助更新:运维利器Puppet实例讲解(一)
  3. 运维案例:Puppet如何成为数据中心扩张的关键

【责任编辑:李晶 TEL:(010)68476606】

责任编辑:黄丹 来源: puppet-manifest-share
相关推荐

2009-01-03 08:56:00

局域网服务优化

2013-10-17 15:51:29

系统

2009-01-11 09:26:00

局域网本地连接

2019-09-03 10:05:27

Linux监控系统

2021-02-01 17:29:19

FlutterHello World开发

2020-04-23 16:04:25

代码编辑器工具程序员

2011-12-01 20:34:55

iOS

2016-01-05 15:40:07

2021-08-24 00:13:23

Windows 10Windows微软

2019-11-28 16:48:00

华为Mate X

2018-02-08 09:34:34

2014-07-14 16:43:39

华为

2012-05-07 08:57:56

puppet extlpuppet hier

2012-09-04 14:52:28

Puppet

2011-08-23 13:16:41

SQLEXPLAIN

2024-06-21 09:37:02

DefPython函数

2010-09-06 13:15:48

CSS定位

2009-12-18 15:06:10

Ruby常用库

2010-11-11 10:18:59

select into
点赞
收藏

51CTO技术栈公众号