puppet(4)-类、模版语言、模块
代码重用: class, module
类
类是用于公共目的的一组资源,是命名的代码块,创建后可在puppet全局进行调用,类可以继承类是我们构建模块的基本组件
类:命名的puppet代码块,好处就是可以重复调用,需要时可通过名称进行调用;
class my_class {
...puppet code...
}
puppet code: 包含变量赋值、各种条件判断语句、资源声明等等;
注意: 类的名字只能以小写字母开头
调用类:
include class1, class2, ...
class {‘classname‘: }
每个类都会引入一个新的变量scope(作用域),这意味着在任何时候访问类的变量时,都得使用其完全限定名称,不过,在本地scope可以重新为top scope中的变量赋于一个新值
写法举例一:
class apache{
package{‘httpd‘:
ensure => installed,
}
file{‘httpd.conf‘:
path => ‘/etc/httpd/conf/httpd.conf‘,
ensure => file,
require => Package[‘httpd‘],
}
service{‘httpd‘:
ensure => running,
require => Package[‘httpd‘],
subsribe => File[‘httpd.conf‘],
}
}
写法举例二:
class nginx{
$webserver=‘nginx‘
package{$webserver:
ensure => latest,
}
file{"/etc/$webserver/nginx.conf":
ensure => file,
source => "/opt/puppet/modules/$webserver/files/nginx.conf",
require => Package[$webserver],
# notify => Service[‘nginx‘],
}
service{$webserver:
ensure => running,
enable => true,
hasstatus => true,
hasrestart => true,
# restart => ‘systemctl reload nginx.service‘,
require => [ Package[$webserver], File["/etc/$webserver/nginx.conf"]],
subscribe => File["/etc/$webserver/nginx.conf"],
}
}
class {‘nginx‘:
}
类的声明有四种方法:
1.使用include
2.使用require
3.像声明一个资源一样声明类
4.使用ENC的风格来声明一个类
1&3是最常用的
第一种:include base::linux,apache 可以用逗号隔开声明多个类
include nginx
第二种: require apache这种方式很少用
第三种:
class {‘nginx‘:
version => ‘2.2.21‘
}
可以传入参数,所以很常用
注意:类只有在声明后方才执行
定义带参数的类:
class my_class ($para1=value1, $para2=value2) {
...puppet code...
}
调用时,传递参数:
class {‘class_name‘:
para1 => new_value1,
para2 => new_value2,
}
写法举例一:
class createuser ($grpname=testgrp,$username=testuser) {
group{"$grpname":
ensure => present,
}
user{"$username":
ensure => present,
gid => $grpname,
}
}
class {‘createuser‘:
grpname => mageedu,
username => mageedu,
}
写法举例二:
class nginx ($webserver=‘nginx‘){
package{$webserver:
ensure => latest,
}
file{"/etc/$webserver/nginx.conf":
ensure => file,
source => "/opt/puppet/modules/$webserver/files/nginx.conf",
require => Package[$webserver],
# notify => Service[‘nginx‘],
}
service{$webserver:
ensure => running,
enable => true,
hasstatus => true,
hasrestart => true,
# restart => ‘systemctl reload nginx.service‘,
require => [ Package[$webserver], File["/etc/$webserver/nginx.conf"]],
subscribe => File["/etc/$webserver/nginx.conf"],
}
}
class {‘nginx‘:
$webserver = ‘nginx’,
}
类的继承:
定义方式:class base_class_name { ... puppet code ... } class base_class_name::class_name inherits base_class_name { ...puppet code... }
base_class_name::class_name 这是继承类命名的一种规范,让你一眼就知道这是继承某个类的子类(它只是一个名字,没有任何作用,不这样写你会以为它没有继承其他类,这种命名方式叫做完全限定名称)
inherits base_class_name 表示继承哪个类
类的继承这种写法的作用:继承一个已有的类,并实现覆盖资源属性,或向资源属性追加额外值
比如说我之前定义了一个类,这个类就定义了一个package资源-安装了nginx, 然后我现在又想定义一个类 有修改配置文件和 启动服务的资源,这时候就可以继承类。
(1) 继承资源属性;
(2) 覆盖资源属性;
=>
(3) 追加资源属性;
+>
类在实现继承时有几个要点:(1) 声明子类时,其基类会被首先声明; (2) 基类成为子类的父作用域,因为基类变量和属性默认值会被子类直接复制一份 (3) 子类可以覆盖父类中同一资源的相同属性值
继承类的实例:
class nginx { package {‘nginx‘: ensure => latest, } -> service {‘nginx‘: enable => true, ensure => running, hasrestart => true, hasstatus => true, restart => ‘service nginx reload‘ } } class nginx::webserver inherits nginx { file{‘/etc/nginx/nginx.conf‘: source => ‘/opt/puppet/modules/nginx/files/nginx_web.conf‘ ensure => file, notify => Service[‘nginx‘], } } class nginx::haproxy inherits nginx { file{‘/etc/nginx/nginx.conf‘: source => ‘/opt/puppet/modules/nginx/files/nginx_proxy.conf‘ ensure => file, notify => Service[‘nginx‘], } }
以上puppet code 定义了一个基类实现程序包的安装,此外我们额外定义了两个子类,分别实现 webserver 和 proxy功能。
但是一台机器上怎么声明呢?一个节点不能带两种角色,什么时候用呢?
将来我们做master/agent模型,两个node ,第一个node include nginx::webserver这个类,另外一个node include nginx::haproxy可以引用测试: include nginx::webserver
高级继承:
继承后子类改父类资源中属性的值:class nginx { package {‘nginx‘: ensure => latest, } -> service {‘nginx‘: enable => true, ensure => running, hasrestart => true, hasstatus => true, restart => ‘service nginx reload‘ } } class nginx::webserver inherits nginx { Package[‘nginx‘]{ ##这里是资源引用 大写[‘tittle‘] name => ‘tengine‘, } file{‘/etc/nginx/nginx.conf‘: source => ‘/opt/puppet/modules/nginx/files/nginx_web.conf‘ ensure => file, notify => Service[‘nginx‘], } } class nginx::haproxy inherits nginx { file{‘/etc/nginx/nginx.conf‘: source => ‘/opt/puppet/modules/nginx/files/nginx_proxy.conf‘ ensure => file, notify => Service[‘nginx‘], } } 从新定义父资源中的属性时要使用资源引用 即 Package[‘nginx‘]{ name => ‘tengine‘, } 在子类总不仅可以修改属性,还可以加 比如: Package[‘nginx‘]{ name +> ‘varnish‘, }
有了类我们就可以组织模块了,不过为了让模块功能更加强大,我们可以在puppet中使用模版,那么我们就要学习puppet的模版语言。
学习模版语言之前我们先想下,模版语言有什么作用?
举个例子,前面我们 定义了nginx类,类中定义了package资源,file资源,service资源。 其中file资源定义的是 nginx的配置文件,配置文件里有一个配置项需要根据服务器的cpu个数,如何灵活的根据服务器cpu的个数来配置nginx中的这一项参数呢?写死是一种方式,然后在拷贝多个配置文件,定义不同的子类,子类在重新定义file资源中的source属性,也可以实现,但是不是很繁琐,所以我们可以想象有这么一种方式,在nginx.conf文件中定义一个变量,变量的值就是取服务器的cpu个数,那么静态文件中定义变量,用什么来解释呢。在puppet中当然就由puppet来解释,而这种在静态文件中定义变量以及写逻辑判断的做法就叫做模版语言。所以我觉得模版语言 其实就是针对file资源使用的语言。puppet是ruby语言开发的,所以puppet 模版文件中嵌套的语言也是ruby语言。
模版:基于ERB嵌入式的ruby模版语言,他表示在静态文件中使用变量等编程元素生成适用于多种环境的文本文件(配置文件)。Embedded Ruby简称ERB,它主要用于实现在文本文件嵌入ruby代码。原来的文本信息不回被改变,但是ruby代码会执行。执行的结果将直接替换原来的代码处:
语法: <%= Ruby Expression %>: 替换为表达式的值; <% Ruby Expression %>: 仅执行代码,而不替换。 <%# comment %>: 文本注视 <%% 表示转义符 输出为<%这个符号,一般用不到 %%> 输出为 %> ,用不到 <%- Ruby code %>, 忽略空白字符 <% Ruby code -%> ,忽略空白行。 能够用到的只有第一种 模版语言中可以使用puppet中的任意可用变量,但是变量名要以@符号开头。 在模版中还可以使用循环 ,条件判断等各种复杂语法格式。 条件判断: <% if condition -%> some text <% else %> some other text <% end %> 迭代,像for循环 <% @ArrayName.echo do | variable_name %> some text with <%- variable_name %> <% end %> 这里ArrayName是 puppet的一个数组变量。 variable_name 为赋值给的变量,相当于 for i in list ,list是ArrayName , i是 variable_name 条件和迭代 不要求会,能看懂别人写的代码就行 了,关键我们会使用变量就行了。比如上面说到nginx的配置文件问题。
如何在资源定义中引用模版?
首先我们把file文件的source 改成关于启动进程的部分改成如下:
user nginx; worker_processes <%= @processorcount %>; error_log /var/log/nginx/error.log; pid /run/nginx.pid;
对于这种含有模版语言的文件,我们应用到file资源属性要改变一下用法了,不能用source 属性,改用 content属性以及 puppet内置的模版函数template() ,具体如下:
class nginx { package {‘nginx‘: ensure => latest, } -> service {‘nginx‘: enable => true, ensure => running, hasrestart => true, hasstatus => true, restart => ‘service nginx reload‘ } } class nginx::webserver inherits nginx { Package[‘nginx‘]{ name => ‘tengine‘, } file{‘/etc/nginx/nginx.conf‘: source => ‘/opt/puppet/modules/nginx/files/nginx_web.conf‘, ensure => file, notify => Service[‘nginx‘], } } class nginx::haproxy inherits nginx { file{‘/etc/nginx/nginx.conf‘: #source => ‘/opt/puppet/modules/nginx/files/nginx_proxy.conf‘ content => template(‘/opt/puppet/modules/nginx/files/nginx_proxy.conf‘), ensure => file, notify => Service[‘nginx‘], } } include nginx::haproxy
以上就是模版语言,以及模版语言是如何调用的。
modules
puppet模块:为了实现某种完备功能而组织成的一个独立的、自我包含的目录结构
模块名:目录名
目录结构:
modules/
module_name/:
manifests/
init.pp: 必须声明一个类,类名与模块名相同;
*.pp:
MODULE_NAME::[SUBDIR_NAME]::MANIFESTS_FILE_NAME
files/:
静态文件
puppet url:
puppet:///modules/MODULE_NAME/[SUBDIR_NAME]/FILE_NAME
file{‘nginx.conf‘:
source => puppet:///modules/nginx/nginx.conf
}
templates/:
模板文件:*.erb
template(‘MODULE_NAME/TEMPLATE_FILE_NAME‘);
file{‘nginx.conf‘:
content => template(‘模板文件‘),
}
lib/: 插件
tests/: 模块使用说明文档,以及事例example
spec/: lib目录下的插件使用说明文档
puppet model
ACTIONS:
build Build a module release package.
changes Show modified files of an installed module.
generate Generate boilerplate for a new module.
install Install a module from the Puppet Forge or a release archive.
list List installed modules
search Search the Puppet Forge for a module.
uninstall Uninstall a puppet module.
upgrade Upgrade a puppet module.