Puppet:開源系統配置和管理工具
隨着虛擬化和雲計算技術的興起,計算機集群的自動化管理和配置成為了數據中心運維管理的熱點。對於 IaaS、Paas、Saas 來說,隨着業務需求的提升,后台計算機集群的數量也會線性增加。對於數據中心的運維人員來說,如何自動化管理、配置這些大規模的計算機集群節點,對於數據中心的穩定運行以及運維成本控制都顯得至關重要。
Puppet 是一個開源系統配置管理工具,它有着簡明的架構以及良好的擴展性;同時,Puppet 還提供了自有的系統配置描述語言以及完善的公用庫,非常適合用於管理和部署大規模集群系統。
Puppet 的系統架構
Puppet 使用簡明的 C/S 架構,分為 Puppet Server 和 Puppet Node。
圖 1. Puppet 的架構
Puppet Server
Puppet Server 是配置和管理整個集群的大腦,管理着所有節點。系統管理員在 Puppet Server 上用 Puppet 特有的配置描述語言為各個節點編寫配置文件 (manifest),配置文件描述了節點的目標狀態——資源的集合。這些資源可以是文件、服務、軟件包等等。各個節點會周期性的查詢 Puppet Server,獲得自己的最新配置文件,並且在本地應用這些配置文件,使得自身的資源和狀態達到配置文件要求。
Puppet Node(Agent)
被 Puppet Master 管理着的計算機節點稱為 Puppet node。Puppet node 會周期性的查詢 Puppet Master,來獲取自己的配置文件,並且在本地應用。在每次應用配置文件之后,Puppet node 會提供上傳一份報告給 Puppet Master,以便以后的統計和分析。系統管理員也可以手動地在 Puppet Node 上執行命令,讓 Puppet Node 立即查詢 Puppet Server 獲取自身最新的配置文件,並且在本地應用。
Puppet 的工作流程
Puppet 的工作流程可以概括成這幾步:定義、模擬、應用、報告。
圖 2. Puppet 的工作流程
定義 (Define)
管理員為各個節點編寫配置文件,配置文件中定義了該節點所需要的資源的集合以及資源之間的關系。這些資源可以是文件、服務、軟件包、可執行的命令等等。Puppet 內置的配置管理語言對這些資源提供了較為完整的底層抽象,減輕了編寫配置文件的復雜度。
模擬 (Simulate)
根據節點的配置文件,我們可以了解到該節點需要什么樣的資源並且處於什么樣的狀態。配置文件描述了節點的狀態,而不是具體的配置步驟。Puppet 會將配置文件 Manifest 編譯成更為詳細的一種配置文件 Catalog。通過 Catalog,Puppet 會根據節點的當前狀態,模擬出節點達到該目標狀態所需要的步驟。
應用 (Enforce)
節點周期性地向 Puppet Server 來請求自己最新的配置文件。Puppet 會將節點的實際狀態與節點配置文件中所表述的目標狀態做比較,並根據得到的所需要的步驟,對節點執行操作,使其達到配置文件所表述的狀態。
報告 (Report)
當每次應用執行過后,節點都會給 Puppet Server 發送一份運行報告,報告該節點的狀態,以便以后的分析和統計。
Puppet 配置語言介紹
Puppet 配置管理語言中的核心概念是資源,資源可以是一個軟件包,一個文件,一種服務等等。一個節點的狀態可以用資源的集合以及他們之間的關系來表示。管理員不需要詳細地描述配置和部署系統的具體步驟,Puppet 只需要管理員來描述系統的目標狀態,即資源的集合以及它們之間的關系。Puppet 內置的執行引擎會根據節點的現有狀態將配置文件轉化為具體的執行步驟並且執行。
在 Puppet 中,類是一系列相關資源的集合;模塊是一系列類的集合。Puppet 內置提供了一些常用的類和模塊,同時用戶可以定義自己的類和模塊。通過類和模塊使用,配置模塊重用和共享變的非常容易。
安裝和配置
環境配置
由於 Puppet Server 和節點之間通過主機名來通信,所以需要雙方可以通過彼此的主機名來找到對應的 IP 地址。可以通過配置 DNS 或者配置/ets/hosts 文件來實現。
安裝准備
在安裝官方提供的開源版本的 Puppet 軟件之前,Puppet Server 和 agent 首先需要都安裝官方的軟件源 (Puppet 對各種 Linux 發行版都有提供支持,本文以 Ubuntu 14.04 系統為例):
下載官方軟件源的安裝包:
1
|
wget https://apt.puppetlabs.com/puppetlabs-release-pc1-trusty.deb
|
更新軟件源:
1
2
|
sudo dpkg -i puppetlabs-release-pc1-trusty.deb
sudo apt-get update
|
安裝 Puppet Server
1
|
sudo apt-get install puppetserver
|
啟動 PuppetServer
1
|
sudo service puppetservice start
|
安裝 PuppetAgent
1
|
sudo apt-get install puppet-agent
|
編輯/etc/puppetlabs/puppet/puppet.conf 文件,設置該 agent 的 puppet server 的地址:
1
2
|
[main]
server = puppetmaster
|
注:puppetmaster 是 puppetserver 的主機名。
啟動 puppet service
1
|
sudo /opt/puppetlabs/bin/puppet resource service puppet ensure=running enable=true
|
編寫第一個配置文件
第一個 Hello World 配置文件
作為第一個實例配置文件,我們想讓節點做一件最簡單的事情:在/etc/文件夾下面創建一個文件 helloworld.txt,文件的內容是”hello world from puppet!\n”。
首先我們在 puppetserver 上進入/etc/puppetlabs/code/environments/production/manifests 文件夾,創建 site.pp 文件:
1
2
3
4
5
6
7
8
9
10
11
12
|
node puppetagent {
file { 'helloworld':
path => '/etc/helloworld.txt',
owner => 'root',
group => 'root',
mode => '655',
content => "hello world from puppet!\n",
}
}
|
site.pp 就是節點的配置文件,里面可以包含對各個節點的配置描述。在實例配置文件中,”puppetagent”就是節點的主機名。包含在 puppetagent 中的配置描述就是該節點的資源集合的描述。
配置文件創建好后,節點會周期性地查詢 PuppetServer 來獲取自己的配置文件並在本地應用。當然 Puppet 也支持手動獲取自己的配置。在本例中,我們通過手動的方式來進行配置更新。我們在 PuppetAgent 上手動執行命令:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
root@puppetAgent:/opt/puppetlabs/bin# ./puppet agent --test
2016-05-21 14:24:14.858673 WARN puppetlabs.facter - locale environment variables were bad;
continuing with LANG=C LC_ALL=C
Info: Using configured environment 'production'
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Caching catalog for puppetagent
Info: Applying configuration version '1463811856'
Notice: /Stage[main]/Main/Node[puppetagent]/File[helloworld]/ensure:
defined content as '{md5}c3aa68786c58c94ef6f3e2399920f268'
Notice: Applied catalog in 0.02 seconds
root@puppetAgent:/opt/puppetlabs/bin# cat /etc/helloworld.txt
hello world from puppet!
|
我們看到節點成功從 Puppet Server 獲取配置文件,並且在本地應用,對應的文件成功創建。
進階:執行腳本任務
作為進階的任務,我們希望節點可以執行一些更加復雜一點的任務。我們希望節點可以從 PuppetServer 獲取一個命令腳本,並且執行該腳本。
我們首先在/etc/puppetlabs/code/environments/production/modules 中創建一個名叫”test”的模塊,在 test 模塊下面創建一個”files”文件夾。在這個文件夾里的文件是可以被節點獲取的。然后我們在這個”files”文件夾里創建一個 shell 腳本 test.sh,路徑如下:
/etc/puppetlabs/code/environments/production/modules/test/files/test.sh
test.sh 文件內容:
1
2
|
touch /etc/helloworld.log
echo "helloworld" >> /etc/helloworld.log
|
該腳本會在/etc/目錄下創建 helloworld.log 文件,然后在文件里添加”hello world”內容。
進入目錄/etc/puppetlabs/code/environments/production/manifests,然后我們再來編輯 site.pp 文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
node puppetagent {
file { 'test.sh':
path => '/etc/test.sh',
owner => 'root',
group => 'root',
mode => '655',
source => 'puppet:///modules/test/test.sh',
}
exec { 'execute ':
command => 'bash /etc/test.sh',
require => File['test.sh'],
path => ["/bin/"],
}
}
|
其中,我們定義了兩個資源:一個文件資源和一個執行命令資源。同時這兩個資源有依賴關系,命令執行資源依賴於文件資源,所以 Puppet 會優先處理文件資源。執行命令資源會在文件資源存在后再執行。
我們看下客戶端的執行結果:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
root@puppetAgent:/opt/puppetlabs/bin# ./puppet agent --test
2016-05-21 15:39:39.817370 WARN puppetlabs.facter - locale environment variables were bad;
continuing with LANG=C LC_ALL=C
Info: Using configured environment 'production'
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Caching catalog for puppetagent
Info: Applying configuration version '1463816381'
Notice: /Stage[main]/Main/Node[puppetagent]/File[test.sh]/ensure:
defined content as '{md5}2ce060ad2ddab2fe416ca8fb6f8da32a'
Notice: /Stage[main]/Main/Node[puppetagent]/Exec[execute ]/returns: executed successfully
Notice: Applied catalog in 0.05 seconds
root@puppetAgent:/opt/puppetlabs/bin# cat /etc/helloworld.log
helloworld
|
我們可以看到,helloworld.log 文件被正確的創建,說明腳本文件被正確地執行。
總結
Puppet 是基於 Ruby 的開源系統配置和管理工具,它提供的獨特的系統配置語言極大程度地簡化了系統管理員管理和配置系統的過程。本文首先介紹了 Puppet 的系統架構和工作流程,並且介紹了 Puppet 獨特的系統配置語言,之后我們簡單介紹了安裝和配置 Puppet 的具體步驟。最后,本文以兩個實例介紹了如何在 Puppet 中為節點編寫配置文件,來達到創建文件和執行命令的效果。希望本文能對系統管理員,Puppet 初學者有所幫助。
一、puppet 介紹
1、puppet是什么
puppet
是一個IT基礎設施自動化管理工具,它能夠幫助系統管理員管理基礎設施的整個生命周期: 供應(provisioning)、配置(configuration)、聯動(orchestration)及報告(reporting)。
基於puppet ,可實現自動化重復任務、快速部署關鍵性應用以及在本地或雲端完成主動管理變更和快速擴展架構規模等。
遵循GPL 協議(2.7.0-), 基於ruby
語言開發。
2.7.0 以后使用(Apache 2.0 license)
對於系統管理員是抽象的,只依賴於ruby
與facter
。
能管理多達40 多種資源,例如:file
、user
、group
、host
、package
、service
、cron
、exec
、yum repo
等。
2、puppet的工作機制
1)工作模型
puppet 通過聲明性、基於模型的方法進行IT自動化管理。
定義:通過puppet 的聲明性配置語言定義基礎設置配置的目標狀態;
模擬:強制應用改變的配置之前先進行模擬性應用;
強制:自動、強制部署達成目標狀態,糾正任何偏離的配置;
報告:報告當下狀態及目標狀態的不同,以及達成目標狀態所進行的任何強制性改變;
puppet三層模型
puppet三層模型如下:

2)工作流程

3)使用模型
puppet的使用模型分為單機使用模型和master/agent模型,下面我們來看看這兩個模型的原理圖。
單機使用模型
實現定義多個manifests --> complier --> catalog --> apply

master/agent模型
master/agent模型實現的是集中式管理,即 agent 端周期性向 master 端發起請求,請求自己需要的數據。然后在自己的機器上運行,並將結果返回給 master 端。
架構和工作原理如下:
架構

工作原理

3、puppet 名詞解釋
- 資源:是puppet的核心,通過資源申報,定義在資源清單中。相當於
ansible
中的模塊,只是抽象的更加徹底。 - 類:一組資源清單。
- 模塊:包含多個類。相當於
ansible
中的角色。 - 站點清單:以主機為核心,應用哪些模塊。
二、puppet 資源詳解
接下來,我們就以單機模式來具體介紹一下puppet
的各個部分。
1、程序安裝及環境
首先,我們還是來安裝一下puppet
,puppet
的安裝可以使用源碼安裝,也可以使用rpm(官方提供)、epel源、官方提供的yum倉庫來安裝(通過下載官方提供的rpm包可以指定官方的yum倉庫)。
在這里,我們就是用 yum 安裝的方式。
yum install -y puppet
安裝完成過后,我們可以通過rpm -ql puppet | less
來查看一下包中都有一些什么文件。
其中主配置文件為/etc/puppet/puppet.conf
,使用的主程序為/usr/bin/puppet
。
2、puppet 資源簡介
1)資源抽象
puppet 從以下三個維度來對資源完成抽象:
- 相似的資源被抽象成同一種資源**“類型”** ,如程序包資源、用戶資源及服務資源等;
- 將資源屬性或狀態的描述與其實現方式剝離開來,如僅說明安裝一個程序包而不用關心其具體是通過yum、pkgadd、ports或是其它方式實現;
- 僅描述資源的目標狀態,也即期望其實現的結果,而不是其具體過程,如“確定nginx 運行起來” 而不是具體描述為“運行nginx命令將其啟動起來”;
這三個也被稱作puppet 的資源抽象層(RAL)
RAL 由type( 類型) 和provider( 提供者,即不同OS 上的特定實現)組成。
2)資源定義
資源定義通過向資源類型的屬性賦值來實現,可稱為資源類型實例化;
定義了資源實例的文件即清單,manifest;
定義資源的語法如下:
type {'title':
attribute1 => value1,
atrribute2 => value2,
……
}
注意:type必須使用小寫字符;title是一個字符串,在同一類型中必須惟一;每一個屬性之間需要用“,”隔開,最后一個“,”可省略。
例如,可以同時有名為nginx 的“service”資源和“package”資源,但在“package” 類型的資源中只能有一個名為“nginx”的資源。
3)資源屬性中的三個特殊屬性:
Namevar
:可簡稱為name;ensure
:資源的目標狀態;Provider
:指明資源的管理接口;
3、常用資源總結
1)查看資源
我們可以使用puppet describe
來打印有關Puppet資源類型,提供者和元參數的幫助。使用語法如下:
puppet describe [-h|--help] [-s|--short] [-p|--providers] [-l|--list] [-m|--meta] [type]
-l:列出所有資源類型;
-s:顯示指定類型的簡要幫助信息;
-m:顯示指定類型的元參數,一般與-s一同使用;
2)group:管理系統上的用戶組。
查看使用幫助信息:

屬性:
name:組名,可以省略,如果省略,將繼承title的值;
gid:GID;
system:是否為系統組,true OR false;
ensure:目標狀態,present/absent;
members:成員用戶;
簡單舉例如下:
vim group.pp
group{'mygrp':
name => 'mygrp',
ensure => present,
gid => 2000,
}
我們可以來運行一下:

3)user:管理系統上的用戶。
查看使用幫助信息:

屬性:
name:用戶名,可以省略,如果省略,將繼承title的值;
uid: UID;
gid:基本組ID;
groups:附加組,不能包含基本組;
comment:注釋;
expiry:過期時間 ;
home:用戶的家目錄;
shell:默認shell類型;
system:是否為系統用戶 ;
ensure:present/absent;
password:加密后的密碼串;
簡單舉例如下:
vim user1.pp
user{'keerr':
ensure => present,
system => false,
comment => 'Test User',
shell => '/bin/tcsh',
home => '/data/keerr',
managehome => true,
groups => 'mygrp',
uid => 3000,
}
4)package:puppet的管理軟件包。
查看使用幫助信息:

屬性:
ensure:installed, present, latest, absent, any version string (implies present)
name:包名,可以省略,如果省略,將繼承title的值;
source:程序包來源,僅對不會自動下載相關程序包的provider有用,例如rpm或dpkg;
provider:指明安裝方式;
簡單舉例如下:
vim package1.pp
package{'nginx':
ensure => installed,
procider => yum
}
5)service:定義服務的狀態
查看使用幫助信息:
puppet describe service -s -m

屬性:
ensure:服務的目標狀態,值有true(running)和false(stopped)
enable:是否開機自動啟動,值有true和false
name:服務名稱,可以省略,如果省略,將繼承title的值
path:服務腳本路徑,默認為/etc/init.d/下
start:定制啟動命令
stop:定制關閉命令
restart:定制重啟命令
status:定制狀態
簡單舉例如下:
vim service1.pp
service{'nginx':
ensure => true,
enable => false
}
6)file:管理文件、目錄、軟鏈接
查看使用幫助信息:

屬性:
ensure:目標狀態,值有absent,present,file,directory和link
file:類型為普通文件,其內容由content屬性生成或復制由source屬性指向的文件路徑來創建;
link:類型為符號鏈接文件,必須由target屬性指明其鏈接的目標文件;
directory:類型為目錄,可通過source指向的路徑復制生成,recurse屬性指明是否遞歸復制;
path:文件路徑;
source:源文件;
content:文件內容;
target:符號鏈接的目標文件;
owner:定義文件的屬主;
group:定義文件的屬組;
mode:定義文件的權限;
atime/ctime/mtime:時間戳;
簡單舉例如下:
vim file1.pp
file{'aaa':
path => '/data/aaa',
source => '/etc/aaa',
owner => 'keerr',
mode => '611',
}
7)exec:執行命令,慎用。通常用來執行外部命令
查看使用幫助信息:
puppet describe exec -s -m

屬性:
command(namevar):要運行的命令;
cwd:指定運行該命令的目錄;
creates:文件路徑,僅此路徑表示的文件不存在時,command方才執行;
user/group:運行命令的用戶身份;
path:指定命令執行的搜索路徑;
onlyif:此屬性指定一個命令,此命令正常(退出碼為0)運行時,當前command才會運行;
unless:此屬性指定一個命令,此命令非正常(退出碼為非0)運行時,當前command才會運行;
refresh:重新執行當前command的替代命令;
refreshonly:僅接收到訂閱的資源的通知時方才運行;
簡單舉例如下:
vim exec1.pp
exec{'cmd':
command => 'mkdir /data/testdir',
path => ['/bin','/sbin','/usr/bin','/usr/sbin'],
# path => '/bin:/sbin:/usr/bin:/usr/sbin',
}
8)cron:定義周期性任務
查看使用幫助信息:

屬性:
command:要執行的任務(命令或腳本);
ensure:目標狀態,present/absent;
hour:時;
minute:分;
monthday:日;
month:月;
weekday:周;
user:以哪個用戶的身份運行命令(默認為root);
target:添加為哪個用戶的任務;
name:cron job的名稱;
簡單舉例如下:
vim cron1.pp
cron{'timesync':
command => '/usr/sbin/ntpdata 172.16.0.1',
ensure => present,
minute => '*/3',
user => 'root',
}
我們可以運行一下,查看我們的crontab,來看看該任務是否已經被添加:
[root@master manifests]# puppet apply -v --noop cron1.pp #試運行
[root@master manifests]# puppet apply -v cron1.pp #運行
[root@master manifests]# crontab -l #查看計划任務
# HEADER: This file was autogenerated at 2017-12-14 15:05:05 +0800 by puppet.
# HEADER: While it can still be managed manually, it is definitely not recommended.
# HEADER: Note particularly that the comments starting with 'Puppet Name' should
# HEADER: not be deleted, as doing so could cause duplicate cron jobs.
# Puppet Name: timesync
*/3 * * * * /usr/sbin/ntpdata 172.16.0.1
9)notify:調試輸出
查看使用幫助信息:

屬性:
message:記錄的信息
name:信息名稱
該選項一般用於master/agent模式
中,來記錄一些操作的時間,比如重新安裝了一個程序呀,或者重啟了應用等等。會直接輸出到代理機的運行日志中。
以上,就是我們常見的8個資源。其余的資源我們可以使用puppet describe -l
來列出,上文中也已經說過了~
4、資源的特殊屬性
puppet
中也提供了before、require、notify和subscribe四個參數來定義資源之間的依賴關系和通知關系。
before:表示需要依賴於某個資源
require:表示應該先執行本資源,在執行別的資源
notify:A notify B:B依賴於A,且A發生改變后會通知B;
subscribe:B subscribe A:B依賴於A,且B監控A資源的變化產生的事件;
同時,依賴關系還可以使用->
和~>
來表示:
-> 表示后資源需要依賴前資源
~> 表示前資源變動通知后資源調用
舉例如下:
vim file.pp
file{'test.txt': #定義一個文件
path => '/data/test.txt',
ensure => file,
source => '/etc/fstab',
}
file{'test.symlink': #依賴文件建立超鏈接
path => '/data/test.symlink',
ensure => link,
target => '/data/test.txt',
require => File['test.txt'],
}
file{'test.dir': #定義一個目錄
path => '/data/test.dir',
ensure => directory,
source => '/etc/yum.repo.d/',
recurse => true,
}
我們還可以使用在最下面統一寫依賴關系的方式來定義:
vim redis.pp
package{'reids':
ensure => installed,
}
file{'/etc/redis.conf':
source => '/root/manifets/files/redis.conf',
ensure => file,
owner => redis,
group => root,
mode => '0640',
}
service{'redis':
ensure => running,
enable => true,
hasrestart => true,
}
Package['redis'] -> File['/etc/redis.conf'] -> Service['redis'] #定義依賴關系
tag 標簽
如同 anssible 一樣,puppet 也可以定義“標簽”——tag,打了標簽以后,我們在運行資源的時候就可以只運行某個打過標簽的部分,而非全部。這樣就更方便於我們的操作。
一個資源中,可以有一個tag
也可以有多個。具體使用語法如下:
type{'title':
...
tag => 'TAG1',
}
type{'title':
...
tag => ['TAG1','TAG2',...],
}
調用時的語法如下:
puppet apply --tags TAG1,TAG2,... FILE.PP
實例
首先,我們去修改一下redis.pp
文件,添加一個標簽進去
vim redis.pp
package{'redis':
ensure => installed,
}
file{'/etc/redis.conf':
source => '/root/manifets/file/redis.conf',
ensure => file,
owner => redis,
group => root,
mode => '0640',
tag => 'instconf' #定義標簽
}
service{'redis':
ensure => running,
enable => true,
hasrestart => true,
}
Package['redis'] -> File['/etc/redis.conf'] -> Service['redis']
然后,我們手動先開啟redis
服務:
systemctl start redis
現在,我們去修改一下file
目錄下的配置文件:
vim file/redis.conf
requirepass keerya
接着,我們就去運行redis.pp
,我們的配置文件已經修改過了,現在想要實現的就是重啟該服務,實現,需要使用密碼keer
登錄:
puppet apply -v --tags instconf redis.pp

現在,我們就去登錄一下redis看看是否生效:
redis-cli -a keerya

驗證成功,實驗完成。
5、puppet 變量
puppet 變量以“$”開頭,賦值操作符為“=”,語法為$variable_name=value
。
數據類型:
字符型:引號可有可無;但單引號為強引用,雙引號為弱引用;支持轉義符;
數值型:默認均識別為字符串,僅在數值上下文才以數值對待;
數組:[]中以逗號分隔元素列表;
布爾型值:true, false;不能加引號;
hash:{}中以逗號分隔k/v數據列表; 鍵為字符型,值為任意puppet支持的類型;{ ‘mon’ => ‘Monday’, ‘tue’ => ‘Tuesday’, };
undef:從未被聲明的變量的值類型;
正則表達式:
(?<ENABLED OPTION>:<PATTERN>)
(?-<DISABLED OPTION>:<PATTERN>)
OPTIONS:
i:忽略字符大小寫;
m:把.當換行符;
x:忽略<PATTERN>中的空白字符;
(?i-mx:PATTERN)
注意:不能賦值給變量,僅能用在接受=~
或!~
操作符的位置;
1)puppet的變量種類
puppet 種類有三種,為facts
,內建變量
和用戶自定義變量
。
facts:
由facter提供;top scope;
內建變量:
master端變量
$servername, $serverip, $serverversion
agent端變量
$clientcert, $clientversion, $environment
parser變量
$module_name
用戶自定義變量
2)變量的作用域
不同的變量也有其不同的作用域。我們稱之為Scope
。
作用域有三種,top scope,node scope,class scope。
其生效范圍排序為:top scope > node scope > class scope

其優先級排序為:top scope < node scope < class scope
6、puppet 流程控制語句
puppet 支持if 語句,case 語句和selector 語句。
1)if 語句
if語句支持單分支,雙分支和多分支。具體語法如下:
單分支:
if CONDITION {
statement
……
}
雙分支:
if CONDITION {
statement
……
}
else{
statement
……
}
多分支:
if CONDITION {
statement
……
}
elsif CONDITION{
statement
……
}
else{
statement
……
}
其中,CONDITION的給定方式有如下三種:
- 變量
- 比較表達式
- 有返回值的函數
舉例
vim if.pp
if $operatingsystemmajrelease == '7' {
$db_pkg='mariadb-server'
}else{
$db_pkg='mysql-server'
}
package{"$db_pkg":
ensure => installed,
}
2)case 語句
類似 if 語句,case 語句會從多個代碼塊中選擇一個分支執行,這跟其它編程語言中的 case 語句功能一致。
case 語句會接受一個控制表達式和一組 case 代碼塊,並執行第一個匹配到控制表達式的塊。
使用語法如下:
case CONTROL_EXPRESSION {
case1: { ... }
case2: { ... }
case3: { ... }
……
default: { ... }
}
其中,CONTROL_EXPRESSION的給定方式有如下三種:
- 變量
- 表達式
- 有返回值的函數
各case的給定方式有如下五種:
- 直接字串;
- 變量
- 有返回值的函數
- 正則表達式模式;
- default
舉例
vim case.pp
case $osfamily {
"RedHat": { $webserver='httpd' }
/(?i-mx:debian)/: { $webserver='apache2' }
default: { $webserver='httpd' }
}
package{"$webserver":
ensure => installed, before => [ File['httpd.conf'], Service['httpd'] ],
}
file{'httpd.conf':
path => '/etc/httpd/conf/httpd.conf',
source => '/root/manifests/httpd.conf',
ensure => file,
}
service{'httpd':
ensure => running,
enable => true, restart => 'systemctl restart httpd.service',
subscribe => File['httpd.conf'],
}
3)selector 語句
Selector 只能用於期望出現直接值(plain value) 的地方,這包括變量賦值、資源屬性、函數參數、資源標題、其它 selector。
selector 不能用於一個已經嵌套於於selector 的case 中,也不能用於一個已經嵌套於case 的case 語句中。
具體語法如下:
CONTROL_VARIABLE ? {
case1 => value1,
case2 => value2,
...
default => valueN,
}
其中,CONTROL_EXPRESSION的給定方式有如下三種:
- 變量
- 表達式
- 有返回值的函數
各case的給定方式有如下五種:
- 直接子串;
- 變量;
- 有返回值的函數;
- 正則表達式模式;
- default
selectors 使用要點:
- 整個selector 語句會被當作一個單獨的值,puppet 會將控制變量按列出的次序與每個case 進行比較,並在遇到一個匹配的 case 后,將其值作為整個語句的值進行返回,並忽略后面的其它 case。
- 控制變量與各 case 比較的方式與 case 語句相同,但如果沒有任何一個 case 與控制變量匹配時,puppet 在編譯時將會返回一個錯誤,因此,實踐中,其必須提供default case。
- selector 的控制變量只能是變量或有返回值的函數,切記不能使用表達式。
- 其各 case 可以是直接值(需要加引號) 、變量、能調用返回值的函數、正則表達式模式或 default。
- 但與 case 語句所不同的是,selector 的各 case 不能使用列表。
- selector 的各 case 的值可以是一個除了 hash 以外的直接值、變量、能調用返回值的函數或其它的 selector。
舉例
vim selector.pp
$pkgname = $operatingsystem ? {
/(?i-mx:(ubuntu|debian))/ => 'apache2',
/(?i-mx:(redhat|fedora|centos))/ => 'httpd',
default => 'httpd',
}
package{"$pkgname":
ensure => installed,
}
寫在后面
以上,我們本次的介紹就告一段落,剩余的部分,請看下回分解。
作者:珂兒吖
出處:http://www.cnblogs.com/keerya/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。
大家寫文都不容易,希望尊重勞動成果喲~