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! ”。
首先我们在 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!
", } } |
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/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
大家写文都不容易,希望尊重劳动成果哟~