磨刀不誤砍柴工 Puppet語法詳解
本文將介紹puppet的語法,因?yàn)閜uppet是用ruby編寫的,因此puppet的語法也和ruby類似,都是很簡單的面對對象的高級語言。再次強(qiáng)調(diào),puppet把需要管理的內(nèi)容抽象成為資源,每種資源有不同的屬性,因此puppet語言就是描述這些資源的屬性以及資源之間關(guān)系的語言。
一、資源
定義一個(gè)資源,需要指定資源的類型和資源的title。看一個(gè)例子:
f i l e { " / etc /passwd" : name => " / etc / passd " , owner => root , group => root , mode => 644; }
上面的代碼讓/etc/passwd的權(quán)限保持644,并且屬于root用戶和root用戶組,file是指定資源的類型是"file"類型,第二行的"/etc/passwd"是資源的title, title的作用是讓puppet能唯一標(biāo)識這個(gè)資源。第三行的name指定了要對那個(gè)文件操作,默認(rèn)情況下,name都等于title,所以很多時(shí)候name是可以省略的。這點(diǎn)要注意??聪旅娴睦?
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卻可以通過判定操作系統(tǒng)自己選擇合適的值。這樣,當(dāng)其他的資源要依賴sshdconfig的時(shí)候,只需要說明依賴sshdconfig就行,不需要關(guān)心文件到底在什么路徑下面。例如下面的代碼:
s e r v i c e { " sshd " : subscribe => F i l e [ sshdconfig ] , }
指定了一個(gè)sshd的服務(wù),這個(gè)服務(wù)如果發(fā)現(xiàn)文件資源sshdconfig 有變動,就會自己reload配置文件。是不是很方便呢?注意上面的subscribe后面的File,第一個(gè)字母要大寫,定義資源關(guān)系的時(shí)候,這里的字母要大寫。
通常,在puppet代碼里面可能會定義很多相同的資源,可以用[]把所有資源的title寫在一起,例如:
f i l e { [ " / etc /passwd" , " / etc / hosts " ] : owner => root , group => root , mode => 644; }
你可能已經(jīng)發(fā)現(xiàn)了,每次定義文件的時(shí)候如果都輸入mode,owner,group會很繁瑣,因此你可以在puppet的site.pp的開頭定義資源的默認(rèn)值。定義資源的默認(rèn)值需要把資源的第一個(gè)資源大寫。例如下面的代碼讓所有的file資源的mode是644,owner是root。
F i l e { owner => root , mode => 644 ; }
默認(rèn)值可以被后面的設(shè)置覆蓋。
在puppet里面可以定義資源之間的關(guān)系,例如前面提到的,如果sshdconfig文件如果有修改,sshd服務(wù)就重啟。puppet里面還有另一個(gè)資源關(guān)系,依賴。例如資源A依賴資源B,如果資源B不存在,資源A就不被執(zhí)行。定義資源依賴的屬性是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資源設(shè)置port.conf的內(nèi)容為80,但是在設(shè)置file資源之前,要求apache2這個(gè)軟件包配置好了。#p#
二、 類和函數(shù)
類的作用是把一組資源收集在一個(gè)盒子里面,一起使用,例如把sshd和他的配置文件做成一個(gè)ssh類,其他的地方要用到就直接包含ssh類就可以了,方便寫出更簡潔的代碼,便于維護(hù)。類可以繼承。看一個(gè)具體的例子:
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的內(nèi)容是從puppet服務(wù)器上面下載的,file資源的內(nèi)容可以從別的url得到,也可以erb模板生成,erb模板是很強(qiáng)大的工具,這個(gè)后面會說到。package資源安裝ssh軟件,service資源保證ssh服務(wù)在運(yùn)行狀態(tài)。類的繼承這里就不講了,因?yàn)槭侨腴T手冊,另外用的不多。
puppet的官方文檔里面是沒有puppet函數(shù)這一說法的,而是叫做define ; 這里我寫做函數(shù),是因?yàn)閐efine實(shí)現(xiàn)的功能其實(shí)和函數(shù)一樣,而且在ruby里面也是用define來定義一個(gè)函數(shù)。這里寫做函數(shù),便于理解。
具體來看一個(gè)例子:
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定義了一個(gè)svn_repo函數(shù),并且?guī)Я艘粋€(gè)參數(shù)1 。這個(gè)參數(shù)可以在函數(shù)里面的資源使用,在這里,exec資源根據(jù)提供的參數(shù)創(chuàng)建svn 倉庫。函數(shù)定義好以后,后面的兩行就用定義好的函數(shù)創(chuàng)建了兩個(gè)svn庫。#p#
三、 節(jié)點(diǎn)
puppet如何區(qū)分不同的客戶端,并且給不同的服務(wù)端分配manifest呢?puppet使用叫做node的語法來做這個(gè)事情,node 后面跟客戶端的主機(jī)名3,例如下面的例子:
node ' host1 . example . com ' { include ssh } node ' host2 . example . com ' { include apache , mysql , php }
當(dāng)主機(jī)host1.example.com來連服務(wù)端時(shí),只會執(zhí)行node 'host1.example.com'里面的代碼,不會執(zhí)行node host2.example.com里面的代碼。正如前面所說,可以定義一個(gè)default結(jié)點(diǎn)。比如沒有針對host3的node配置,host3就用default的配置了。在這里include的意思是include 類。同樣,節(jié)點(diǎn)也支持繼承,同樣,也不打算深入。
使用節(jié)點(diǎn)的時(shí)候,盡量把所有的配置寫成類,節(jié)點(diǎn)里面定義好變量和包含相應(yīng)的類就可以了。保證代碼的簡潔。例如:
1、因?yàn)榭梢詭?shù),所以我覺得翻譯成函數(shù)更好
2、注意看函數(shù)的使用語法,是不是和使用資源一樣,path可以看作是屬性
3、主機(jī)名在puppet里面很重要
node ' host4 . example . com ' { $networktype=" t e l e " $nagioscheckport=" 80 ,22 ,3306 " include ssh , apache , mysql }
#p#
四、變量和數(shù)組
puppet也和其他語言一樣,支持變量和數(shù)組,puppet用$符號定義變量,變量的內(nèi)容用雙引號括起來。例如:
$test=" hello , guys " f i l e { " /tmp/ t e s t " : content => $test ; }
puppet可以使用由facter提交的變量,facter在客戶端收集系統(tǒng)信息整理成不同的變量提交給puppet服務(wù)器端,服務(wù)器端的代碼可以使用這些變量實(shí)現(xiàn)高級的功能,例如不同的硬件配置生成不同的應(yīng)用軟件配置文件。運(yùn)行facter命令可以看到很多變量的輸出,這些變量可以在puppet代碼里面直接使用。
puppet利用方括號來定義數(shù)組,數(shù)組的內(nèi)容由逗號分割,例如下面的例子:
[ "apache2" , " httpd " , " ssh " ]
數(shù)組可以用在資源定義里面,例如前面提到的例子。也可以用在函數(shù)里面,例如:
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 ' ] : }
變量也有有效范圍,同其他語言一樣分為局部和全局變量,簡單說來,就是在里面定義的變量的使用范圍就限制在里面。同時(shí),puppet還簡單的支持if ... eles 語法,但是用的不多,不在深入。
#p#
五、 模塊
簡單來說,一個(gè)模塊就是一個(gè)/etc/puppet/modues目錄下面的一個(gè)目錄和它的子目錄,在puppet的主文件site.pp里面用import modulename可以插入模塊。新版本的puppet可以自動插入/etc/puppet/modues目錄下的模塊。引入模塊,可以結(jié)構(gòu)化代碼,便于分享和管理。例如關(guān)于apache的所有配置都寫到apache模塊下面。一個(gè)模塊目錄下面通常包括三個(gè)目錄,files, manifests,templates 。manifests 里面必須要包括一個(gè)init.pp的文件,這是該模塊的初始文件,導(dǎo)入一個(gè)模塊的時(shí)候,會從init.pp開始執(zhí)行。可以把所有的代碼都寫到init.pp里面,也可以分成多個(gè)pp文件,init 再去包含其他文件。
files目錄是該模塊的文件發(fā)布目錄,puppet提供一個(gè)文件分發(fā)機(jī)制,類似rsync的模塊。templates 目錄包含erb模型文件,這個(gè)和file資源的template屬性有關(guān)。
puppet安裝好以后,modules目錄是沒有的,自己建立一個(gè)就行,然后在里面可以新增加你的模塊。請養(yǎng)成使用模塊的習(xí)慣。
【編輯推薦】
- 開源自動化配置管理工具Puppet入門教程
- SVN自助更新:運(yùn)維利器Puppet實(shí)例講解(一)
- 運(yùn)維案例:Puppet如何成為數(shù)據(jù)中心擴(kuò)張的關(guān)鍵
【責(zé)任編輯:李晶 TEL:(010)68476606】