Puppet puppet
概念
三个组件
- Deployment
puppet使用客户端/服务器模型,其服务器称为puppet
master,其客户端称为puppet agent,puppet agent所在主机称为node。
- Configuration Language and Resource Abstraction Layer
shell脚本或perl脚本可称为命令式或过程式的(imperative or
procedural),而puppet则是声明式的,它只声明某个服务应该被启动或安装,至于具体怎么装,那就由puppet来决定。
`` example
type { title:
attribute => value,
}
Puppet" target="_blank">http://docs.puppetlabs.com/references/stable/type.html">Puppet Type
Reference
每种Type都有多个Provider,怎么做(How)是由Provider来实现的。以package
type为例,相应的provider有:yum, aptitude, pkgadd, ports,
emerge等。Puppet通过一个名为Facter的工具来获取agent的信息(如操作系统版本等),根据agent的信息来选择合适的provider。如果agent上运行的操作系统是Red
Hat,那对应的package
provider会是yum,如果是Ubuntu,则会选择aptitude。执行完以后,puppet会返回成功或失败的结果给puppet
master。
Facter是一个ruby工具,用于获取系统的“facts”。在命令行下输入facter即可获得详细列表。
- Transactional Layer
Transactional Layer即是驱动的引擎,包括以下四个步骤:
- Interpret and compile your configuration
分析配置,计算如何应用到agent中。
- Communicate the compiled configuration to the agent
针对每个agent,将resource编译成catalog,并将catalog传给agent所在主机。
- Apply the configuration on the agent
- Report the results of that application to the master
Transaction
Layer具有idempotent(幂等性),即将同一个操作多次应用到同一个主机的,最终的结果是一致的。然而puppet操作是不能撤消的,这与数据库中的Transaction完全不同。不过transaction可以运行在“noop”模式,即可以模拟实际的操作。
<h3 id="安装">安装</h3>
Puppet在2.6.0之后的版本中不再使用XML-RPC,性能上有很大提升,而2.6.0之前的最高版本为0.25.5,0.24.x之前的版本不推荐使用。agent所用版本最好低于master版本,但不可低于0.24.x。
example
gem install puppet facter 用gem来安装可获得最新puppet版本,不再依赖于yum或apt的仓库的版本。
puppet的yum仓库地址为 <http://yum.puppetlabs.com> ,直接安装名为
puppetlabs-release-x-x.noarch.rpm的包即可完成添加puppet仓库。
puppet的apt仓库地址为 <http://apt.puppetlabs.com> ,直接安装名为
puppetlabs-release-xxx.deb的包即可完成apt仓库的添加。
<h3 id="主要配置组件">主要配置组件</h3>
- Resources: Individual configuration items
- Files: Physical files you can serve out to your agents
- Templates: Template files that you can use to populate files
- Nodes: Specifies the configuration of each agent
- Classes: Collections of resources
- Definitions: Composite collections of resources
<h2 id="Module">Module</h2>
Modules are self-contained collections of Puppet code, manifests, Puppet
classes, files, templates, facts, and tests, all for a specific
configuration task. Modules are usually highly reusable and shareable.
模块通常包含了某个应用所需的所有配置信息,比如,一个apache模块包括了apache
Web服务器所需的所有配置。
每个模块都需要有特殊的文件结构,包括一个名为init.pp的文件。在master的modulepath中配置模块所在的目录:
example
[master]
modulepath = /etc/puppet/modules:/var/lib/puppet/modules:/opt/modules
初始化模块目录的代码:
example
mkdir –p /etc/puppet/modules/sudo/{files,templates,manifests}
touch /etc/puppet/modules/sudo/manifests/init.pp
<h2 id="Resource Type">Resource Type</h2>
<h3 id="package中的allow<sub>virtual</sub>">package中的allow<sub>virtual</sub></h3>
allow<sub>virtual参数与virtual</sub> resource没有关系。
package资源类型的provider有很多种,包括常见的apt和yum等。每种provider的特性并不相同,puppet的type文档中可以查到provider
features,其中的virtual<sub>packages特性只有三种provider有</sub>:rpm,yum,zypper。因此,allow<sub>virtual其实只影响这三种provider</sub>。
rpm文档中可以查到virtual
package的概念。rpm包的spec文件中有provides标签,用来标识virtual
package。当不同的包提供了相同的功能时,这个相同的功能就可以用virtual
package来标识。比如,任何提供了阅读邮件功能的包都提供了mail-reader功能。这些包就可声明如下:
example
Provides: mail-reader
参看:Maximum RPM 2nd P233.
<h3 id="user">user</h3>
managehome并不一定在所有系统中都有效,可以查看provider的feature。通过的做法是用户的home目录单独配置。
<h3 id="file">file</h3>
使用recurse=\>true时要小心,如果该目录下文件很多的话,即使一个简单的mode的设置也会耗费很长的时间。
<h3 id="修改文件的部分内容">修改文件的部分内容</h3>
自定义函数的做法:http://projects.puppetlabs.com/projects/puppet/wiki/Simple<sub>TextPatterns</sub>/5
最好的办法是使用stdlib中的file<sub>line方法</sub>。
puppet
file_line { 'sudo_rule':
path => '/etc/sudoers',
line => '%sudo ALL=(ALL) ALL',
}
file_line { 'sudo_rule_nopw':
path => '/etc/sudoers',
line => '%sudonopw ALL=(ALL) NOPASSWD: ALL',
}
<h3 id="vcsrepo">vcsrepo</h3>
注意设置user和owner,user是执行git
clone时的用户,owner是最终repo的拥有者。
要跟踪分支,设置revision参数,如果A仓库没有跟踪远程某个分支,那么再从A仓库clone出去的其它仓库将无法检出该分支。
现要设置A仓库与moodle官方仓库同步,本地其它仓库与A仓库检出:
puppet
vcsrepo { '/opt/gitrepo/moodle.git':
ensure => latest,
provider => 'git',
source => 'https://github.com/moodle/moodle.git',
user => 'git',
owner => 'git',
revision => hiera('moodle_revision'),
require => [ User['git'], File['/opt/gitrepo'] ],
}
其它参数再从这里检出。
<h2 id="hosts文件对node<sub>namevalue的影响</sub>">hosts文件对node<sub>namevalue的影响</sub></h2>
下面的hosts记录:
example
127.0.0.1 localhost node7.soft6
根据hosts文件的语法,localhost为canonical<sub>hostname</sub>,node.soft6为alias。在Ubuntu12.04系统中运行facter,收集到的fqdn会是node7,尽管运行hostname命令得到的是node7.soft6。在删除alias后,得到的fqdn就成了node7.soft6。(别名不会记录点号之后的字符?)配置puppet时不使用别名,就可以避免类似错误出现。
puppet在默认配置情况下,facter收集到的fqdn值会是certname,而certname又决定了ca<sub>name和nodenamevalue的值</sub>,最终在puppetmaster上收集到的node的名字就会是certname的值。整个过程与facter收集到的hostname没有关系。因此,配置puppet的节点的名字,重点是配置/etc/hosts文件。/etc/hostname文件可不用理会。
<h2 id="Language">Language</h2>
<h3 id="Data Types">Data Types</h3>
Boolean类型由true和false两个值,使用时注意不能使用引号。"false"是字符串,转换成Boolean,结果会是true。另外fact中所有变量全部为字符串,使用时需要特别注意。
String有多种形式:
- Bare Words 满足以下两个条件的Bare
Word会被puppet当作字符串来处理:一、不是保留关键词。二、以小写字母开头,并且只包含letters,
digits, hyphens (-), and underscores
(\_)。大写字母开始的词会被当作resource reference来处理。
- Single-Quoted Strings
只允许一种转义字符\\。字符串中的换行会被认为是literal line breaks。
- Double-Quoted Strings 可以用。允许Variable Interpolation、Escape
Sequences、Expression Interpolation。
<h3 id="facts">facts</h3>
facts支持所有的数据类型,然而默认情况下,puppet3.8返回的facts值为字符串,除非使用下面的配置:
example
stringify_facts = false
没有使用该配置的情况下,对于facts变量的值可能需要额外处理。比如\$::is<sub>virtual的值为</sub>"false",由于是字符串,在代码中使用时就得用函数转换:
example
if str2bool("$is_virtual") { ... }
使用fact变量有两种方式:一是使用\$::fact<sub>name</sub>,二是使用\$facts\['fact<sub>name</sub>'\].
前一种方法最常用,从puppet
3.0开始,'::'就是可以省略的,但写上可能更清楚。
第二方法其实是在访问hash,需要添加如下配置后才会启用:
example
trusted_node_data = true
<h3 id="namespace">namespace</h3>
<http://docs.puppetlabs.com/puppet/3.8/reference/lang_namespaces.html>
Class和defined
type可以将名字分隔成多个部分,这些部分就称为namespace,它们是通过'::'来分隔的。名字空间告诉了autoloader如何在module中找到这些class或defined
type。
名字空间的第一部分为module的名字,后面的名字相当于子目录的位置,如下表所示:
| name | file path |
|------------------------|--------------------------------------------------|
| apache | \<modulepath\>/apache/manifests/init.pp |
| apache::mod | \<modulepath\>/apache/manifests/mod.pp |
| apache::mod::passenger | \<modulepath\>/apache/manifests/mod/passenger.pp |
加载名为"foo"的class或defined type时的次序:
- \<current namespace\>::foo
- 如果找不到,就找\<parent of current namespace\>::foo
- 还找不到,就从ancestor namespace中找
- 最后,::foo
我曾经碰到一个比较隐蔽的问题:
puppet
class profile::nginx {
include nginx
}
使用时发现无论怎么用,nginx模块并没有被加载。当我把include改成下面的代码时,相应的模块就被执行了:
example
include ::nginx
究其原因,include
nginx会先加载profile模块中的nginx类,而不会去找nginx模块的nginx类。
<h3 id="Containment">Containment</h3>
Classes和defined
type的实例包含(contain)了它们声明的资源。被包含的资源在容器初始化之前不会被应用,在容器结束之前必会完成。这就意味着如果某个资源或类与某容器形成了关系(relationship),那么它与该容器内的所有资源也有相同的关系。relationship参看metaparameter。
有了包含,就可以notify或subscribe某个class或defined
type,这些class或defined type在使用时与单个资源没什么区别。
native和defined resource
type在声明时就会自动被包含在外部容器(class或defined
type)中。然而,class内部声明的class并不会自动包含在外部容器之中,这是因为class会在很多地方被include,如果每次include都自动包含的话,会导致严重后果。通过显式调用contain函数来包含class,contain能够实现include的功能,还会让class被包含在容器中。
Resource-Like声明的class中使用contain:
puppet
class ntp {
# ...
class { 'ntp::service':
enable => true,
}
contain 'ntp::service'
# ...
}
<h3 id="Variable Scope">Variable Scope</h3>
puppet是一种声明式语言,这种语言不允许对变量重新赋值,因为重新赋值会让变量的值取决于变量被赋值时间的先后。像下面的代码在puppet中会出错:
puppet
node 'pro-puppet.example.com'
{
$location = 'dc1'
...
$location = 'dc2'
}
任何时候,puppet中都有四个有效Scope:top scope, node scope, parent
scope, and local scope。 top scope通过::来引用,比如,\$::osfamily。node
scope没有名字,无法从外部引用,但它在locale scope中却是可用的。
<h3 id="类中的scope">类中的scope</h3>
在nagios::params中定义的参数,即使是在同一个模块中,最好也是通过下面的方式来引用,而不要使用短称:
example
$::nagios::parmas::monitor_pkgs
<h3 id="templates">templates</h3>
<http://docs.puppetlabs.com/puppet/latest/reference/lang_template_erb.html>
- erb的四类标记
\<%= EXPRESSION %\> — Inserts the value of an expression. With -%\>
— Trims the following line break. \<% CODE %\> — Executes code, but
does not insert a value. With \<%- — Trims the preceding
indentation. With -%\> — Trims the following line break. \<%#
COMMENT %\> — Removed from the final output. With -%\> — Trims the
following line break. \<%% or %%\> — A literal \<% or %\>,
respectively.
- erb中访问puppet variables
erb template有自己的locale scope,它的parent scope为加载erb
template文件所在的class或自定义resource type。这也就意味着erb
template中可直接使用class或type(parent
scope)中的变量,但不能往里面添加新的变量。
erb中访问变量的形式有两种:
- @variable
只能访问当前scope及parent scope中的变量
- scope\['variable'\]
可访问其它scope中的变量,如:
example
scope['ntp::tinker']
在erb中访问变量时,会把puppet type转换成ruby类。
| Puppet type | Ruby class |
|---------------------|--------------------------------------------------------------------------------|
| Boolean | Boolean |
| Undef | NilClass (value nil) |
| String | String |
| Number | subtype of Numeric |
| Array | Array |
| Hash | Hash |
| Default | Symbol (value :default) |
| Regexp | Regexp |
| Resource reference | Puppet::Pops::Types::PResourceType, or Puppet::Pops::Types::PHostClassType |
| Lambda (code block) | Puppet::Pops::Evaluator::Closure |
| Data type (Type) | A type class under Puppet::Pops::Types, e.g. Puppet::Pops::Types::PIntegerType |
- erb中调用puppet函数
- All functions are methods on the scope object.
- You must prepend “function\_” to the beginning of the function
name.
- The arguments of the function must be provided as an array, even
if there is only one argument.
example
<%= scope.function_template(["my_module/template2.erb"]) %>
<%= scope.function_warning(["Template was missing some data; this config file may be malformed."]) %>
- 例子
<%# Non-printing tag ↓ -%>
<% if @keys_enable -%>
<%# Expression-printing tag ↓ -%>
keys <%= @keys_file %>
<% unless @keys_trusted.empty? -%>
trustedkey <%= @keys_trusted.join(' ') %>
<% end -%>
<% if @keys_requestkey != '' -%>
requestkey <%= @keys_requestkey %>
<% end -%>
<% if @keys_controlkey != '' -%>
controlkey <%= @keys_controlkey %>
<% end -%>
<% end -%>
<h2 id="Class <span class="tag" tag-name="class"><span class="smallcaps">class</span></span>">Class <span class="tag" tag-name="class"><span class="smallcaps">class</span></span></h2>
<http://docs.puppetlabs.com/puppet/3.8/reference/lang_classes.html>
<h3 id="Include-Like vs. Resource-Like">Include-Like vs. Resource-Like</h3>
Class的使用主要有两种方式:Include-Like vs. Resource-Like。
Include-Like通过以下几个函数来实现:
example
include, require, contain, and hiera_include
这种方式允许你多次声明类,但catalog中只会添加一次。允许class或defined
type自己管理依赖项。通过外部数据来提供类参数。
Include-Like的行为方式如下:
- Request a value from the external data source, using the key \<class
name\>::\<parameter name\>. (For example, to get the apache class’s
version parameter, Puppet would search for apache::version.)
- Use the default value.
- Fail compilation with an error if no value can be found.
Resource-Like只允许声明指定类一次,可以override类参数,如果没有override,才从外部数据加载参数。
Resrouce-Like的行为方式如下:
- Use the override value from the declaration, if present.
- Request a value from the external data source, using the key \<class
name\>::\<parameter name\>. (For example, to get the apache class’s
version parameter, Puppet would search for apache::version.)
- Use the default value.
- Fail compilation with an error if no value can be found.
比较两种行为方式,可以看出,Resource-Like比Include-Like多出了覆盖类参数的步骤。如果要覆盖类参数,必须使用Resource-Like方式。另外覆盖参数也是唯一的,比hiera配置优先级更高参数赋值方式。
<h3 id="Class参数的优先级">Class参数的优先级</h3>
- Explicitly passed parameters
- Hiera data bindings
- Module defaults
<h3 id="require">require</h3>
require会将依赖的类变成它所在容器的依赖项。如:
puppet
define apache::vhost ($port, $docroot, $servername, $vhost_name) {
require apache
...
}
puppet会保证apache中的所有resource会在任一(any)apache::vhost实例之前被应用。include没有这种约束。
require函数的这个特性可用于表达Resource之间的依赖。不过,一般来说,用include函数,再组合Chaining
arrow,可以表示出更复杂的依赖关系。
puppet
class apache::ssl {
include site::certificates
# Restart every service in this class if any of our SSL certificates change on disk:
Class['site::certificates'] ~> Class['apache::ssl']
}
<h2 id="Resource <span class="tag" tag-name="resource"><span class="smallcaps">resource</span></span>">Resource <span class="tag" tag-name="resource"><span class="smallcaps">resource</span></span></h2>
<h3 id="Relationship and Ordering">Relationship and Ordering</h3>
Puppet
manifest文件中定义的资源的应用次序是由puppet根据执行效率的考虑来安排的,与资源在manifest文件中的次序无关。如果要安排次序,那么就必须明确声明资源之间的关联(relationship)。
定义资源之间的关系有三种方式:relationship metaparameters, chaining
arrows, and the require function。 需要注意到relationship
metaparameter中也有requrie,它与require函数并不相同。
- Relationship metaparameter
relationship
metaparameter共有四个:before,subscribe,require和notify。
| Metaparameter | Meaning |
|---------------|-------------------------------------|
| before | applied before the target resource. |
| require | applied after the target resource. |
| notify | before + refresh(–\>) |
| subscribe | after + refresh(\<–) |
before与require是一对,”A在B先“这个意思,可在A用"before=\>B"表示,也可在B中用"require=\>A"表示。notify和subscribe是同样的一对。
ntp服务要求先安装ntp包,可用下面的代码来表示:
bash
service { 'ntp':
ensure => running,
require => Package['ntp'],
}
如果ntp的配置文件发生更改,要重启服务,可用下面的代码来表示:
bash
file { '/etc/ntpd.conf':
source => 'puppet:///modules/admin/ntp.conf',
notify => Service['ntp'],
require => Package['ntp'],
}
四个relationship metaparameter的值都应该是Resource
References(文档在puppet language-\>Data Types-\>Resources
References)。
- Chaining Arrows
四个Relationship
metaparameter其实只是要表达两个意思:一是A在B先,二是A在B先,并且一旦A有改动,就要刷新B,可称为A通知B。
A在B先,可表示成:A -\> B。ordering arrow. A通知B,:A ~\>
B。notification arrow. 上一节例子的过程可用下面的代码来表示:
example
Package['ntp'] -> File['/etc/ntp.conf'] ~> Service['ntp']
Chaining arrow左右两边的操作数只能是以下三种:
- Resource references, including multi-resource references
example
Package['ntp'] -> File['/etc/ntp.conf'] ~> Service['ntpd']
- Resource declarations
puppet
# first:
package { 'openssh-server':
ensure => present,
} -> # and then:
file { '/etc/ssh/sshd_config':
ensure => file,
mode => '0600',
source => 'puppet:///modules/sshd/sshd_config',
} ~> # and then:
service { 'sshd':
ensure => running,
enable => true,
}
- Resource collectors
example
Yumrepo <| |> -> Package <| |>
注意: Arrays of references cannot be chained. 在virtual
resource中使用Chaining arrow是很危险的,因为依赖关系会被实例化。
- Refresh
只有三个build-in的资源类型支持refresh:service, mount, exec。
exec通过不会refresh,但在设置了"refreshonly =\>
true"属性之后,exec就只会在收到refresh事件后才会执行。还可设置exec中的refresh属性,exec在收到refresh事件后就会同时执行两个命令。
- Autorequire
某些资源类型有autorequire,被自动require的资源无需显式声明就会在资源之先加载。如exec中的cwd。
<h3 id="设定Resource的默认值">设定Resource的默认值</h3>
example
File { backup => main, }
设定的file type的默认值。文档位置在Language: Resource Defaults。
<h3 id="自定义Resource Type">自定义Resource Type</h3>
<http://docs.puppetlabs.com/puppet/3.8/reference/lang_defined_types.html>
自定义Resource
Type就是可根据不同参数多次执行的puppet代码块。一旦定义完成,就可像普通resource
type一样来使用,类似于macro。可通过自定义resource
type来开发出功能比较复杂的type来。
define中定义的参数必须带'$',但在使用时就会成为attribute,不再有'$'符号。
example
define apache::vhost ($port, $docroot, $servername = $title, $vhost_name = '*') {...}
apache::vhost {'homepages': port => 8081, docroot => '/var/www-testhost', }
两个不需声明就能直接使用的参数:\$title and
\$name。\$name初始值与\$title相同。每个资源实例必须保证唯一性,\$title在每个实例上必定是唯一的。
自定义Resource Type要在独立的文件中定义,文件名与自定义Resource
Type的名字一致,参考namespace的说明。
<h3 id="Virtual Resources">Virtual Resources</h3>
Virtual
Resource适用于某个资源同时被多个类使用时的情形,这个资源究竟归属哪个Class,很难确定。Virtual
Resource也可解决资源重复定义的问题。 用户帐号是典型的virtual
resource。开发者帐号要安装在开发和测试服务器上,但不能安装在release服务器上,而系统管理员的帐号要安装在所有服务器上。另外,如果在drupal类中定义了Package\['httpd'\],然后又在其它类中单独定义了Package\['httpd'\],那么就会产生资源重复错误。
Virtual Resource需要realize,puppet中有两种方式来realize virtual
resource:
- The “spaceship” syntax \<\| \|\>
- The realize function
使用spaceship时,如果资源无法找到,并不会有错误提示,而realize在使用时如果无法realize,那就会报错。
- Resource Collectors
需要查阅puppet的Language文档,它归在learning目录之下。
<http://docs.puppetlabs.com/puppet/3.8/reference/lang_collectors.html>
resource
collector通过在catalog中根据指定属性搜索出一组resource。catalog就是puppet编译manifests后生成的东西,只对单个node有效,不会有任何歧义内容。
example
User <| title == 'luke' |>
javascript
class webapp {
include accounts::virtual
package { 'webapp': ensure => present }
User <| title == 'mysql'|>
}
使用spaceship能同时收集到多个资源,比如下面的指令能够收集所有apache组的用户:
example
User <| gid == 'apache' |>
还可以表示依赖关系:
example
User <| gid == 'apache' |> { before => Package['apache'] }
上面的语句表示,apache组的帐号要在apache包之前。
- realize
class webapp {
realize(User['mysql]')
package { 'webapp':
ensure => present,
}
}
<h3 id="Exported Resource">Exported Resource</h3>
Exported Resource就是由某node定义,但要应用于其它node的资源。 Virtual
Resource用'@'号表示。Exported Resource用'@@'表示。Exported
Resource表示该资源是virtual,并且向所有其它node开放。exported to all
other nodes using stored
configurations。其它node的catalog就能收集Exported Resource。收集Exported
Resource用'\<\<\| \|\>\>'操作符,比Virtual Resource多一对尖括号。
三个应用场景:
- Automated SSH Public Host Key Management
- Exporting Load Balancer Worker Resources
- Automating Nagios Service Checks
<h2 id="Functions">Functions</h2>
<h3 id="自定义Function的注意点">自定义Function的注意点</h3>
- Function由compiler执行
这就意味着在C/S模型中,Function只会在服务器端执行。
- Function的执行结果会被缓存。 这意味着修改了function就要重启master。
- 只有两种Function:rvalues和statements rvalues在定义时必须声明:type
=\> :rvalue,它会有返回值。而statements无返回值。
- 自定义函数的文件名必须与函数名相同。
- 使用client的fact时,要用lookupvar('FACT<sub>NAME</sub>')
不能用Facter\['FACT NAME'\].value
<h2 id="Hiera <span class="tag" tag-name="hiera"><span class="smallcaps">hiera</span></span>">Hiera <span class="tag" tag-name="hiera"><span class="smallcaps">hiera</span></span></h2>
<h3 id="hiera配置 <span class="tag" tag-name="hiera"><span class="smallcaps">hiera</span></span>">hiera配置 <span class="tag" tag-name="hiera"><span class="smallcaps">hiera</span></span></h3>
默认hiera配置文件为:
yaml
---
:backends:
- yaml
:hierarchy:
- defaults
- %{clientcert}
- %{environment}
- global
hierachy表示了查找的次序,上面的配置中,hiera首先从defaults.yaml文件中找,如果没有找到,会去从%{clientcert}.yaml文件中去找。找到就结束。
<h3 id="Module Data Binding">Module Data Binding</h3>
带参数的Class会使用Hiera来查找参数,这样就不必在参数中使用hiera函数了。
puppet
class science(
$param1 = 'default in module',
$param2 = 'default in module',
$param3 = 'default in module',
){
notify { "param1: ${param1}": }
notify { "param2: ${param2}": }
notify { "param3: ${param3}": }
}
有的参数可以在使用时指定,如:
puppet
class { 'science':
param3 => 'passed in',
}
也有参数可以在hiera中预先配置好,如:
yaml
---
science::param2: 'looked up in hiera'
<h2 id="terminus">terminus</h2>
terminus原义是忒耳弥努斯(界标之神),有“终点、界标”等意思。通过下面的命令查以查看到puppet对terminus的说明:
example
puppet man node
terminus像可puppet与子系统交互的接口。这些子系统可用于访问多个backend的数据,但用统一的接口来访问。所有的indirected
subsystem都能通过rest terminus与puppet master的数据交互。
<h2 id="Forge Module">Forge Module</h2>
<h3 id="apt">apt</h3>
<apt::key的id参数应该是a> full fingerprint (40 characters)。查看nginx
key的fingerprint的命令:
example
gpg --fingerprint signing-key@nginx.com
<h2 id="puppet apply">puppet apply</h2>
两种在puppet控制台输出信息的手段:
- resource type notify
example
puppet apply -e 'notify {"Hello World": }'
- notice() function
example
puppet apply -e 'notice ("Hello World")'
<h2 id="roles and profiles">roles and profiles</h2>
<http://www.craigdunn.org/2012/05/239/>
只使用node和module两层架构,只能处理少量的服务器,当服务器数量达到几百台,类型达到二三十种时,这种方式的管理会很麻烦,解决办法是添加新的抽象层。
在node和module之间添加的两个抽象层,role和profile。
role层面:Development
webserver,这种描述更接近人的描述。根据不同的需要区分出不同的服务器的role。
profile层面:A development webserver has a Tomcat application stack, a
webserver and a local database server.
这个层面要定义出role所需的技术组件。 各个层极相互之间的关系如下: node
1–1 role 1–n profiles 1–n modules 1–n resources
注意,node只能有一个role,role层的主要意义在于提供为node一个更容易识别和管理的名称。
A模块的资源与B模块的资源之间的依赖关系,在profile中定义好。而在模块层面解决这些依赖是非常困难的。
profile层最适合处理module模块及模块之间的关联。如resource chaining,
class overrides and integration with things like Hiera。
从实践角度来看,如果服务器数量还不是太大,那么可去掉role层。
<h2 id="puppetdoc">puppetdoc</h2>
下载地址: <https://docs.puppet.com/puppetdocs-latest.tar.gz> 自行编译:
example
$ VERSION=0.25.0 rake references:puppetdoc
用上面的命令生成puppetdoc时,注意运行命令的机器上不能安装puppet。
<h1 id="Types and Providers">Types and Providers</h1>
<h2 id="Resources">Resources</h2>
Puppet Resoruce的三大特点:
- Declarative
- Idempotent
- Unique
Resource模型由Type和Provider组成。Type规定了用户描述资源的接口,而Provider则封装了在特写平台上管理这些资源的具体步骤。
可用puppet resource命令查看当前系统中资源的状态:
example
$ puppet resource user ftp
用–debug选项可以查看到系统中真正执行的命令:
example
puppet resource user ftp shell=/sbin/nologin --debug
debug: Userftp: Executing '/usr/sbin/usermod -s /sbin/nologin ftp'
还可以查看系统中所有指定类型的资源:
example
puppet resource package
<h2 id="应用Resource的步骤">应用Resource的步骤</h2>
- Users declare the desired state of resources.
- The provider discovers the current state of managed resources.
- Puppet compares each resource’s current state against the desired
state.
- If they are not the same, the provider updates the underlying
system.
- Changes to the underlying system are recorded as events.
加了–noop选项时,第4步会被忽略。
<h2 id="Types">Types</h2>
<h3 id="namevar">namevar</h3>
namevar必须提供资源的唯一标识符。
example
newparam(:name, :namevar => true) do
end
<h3 id="Properties">Properties</h3>
Properties表示系统中资源的状态。每次运行时,puppet都会检查当前资源在系统中Properties的值,并与resource
declaration中的Properties值进行比较。Properties也是Type和Provider的integration
point,Type设定Properties,而Provider则实现了系统中对Properties的管理。
提取Property可问以下两个问题:
- Can I discover the state of this attribute?
- Can I update the state of this attribute?
添加Properties可用newproperty方法:
example
newproperty(:version) do
end
ensure property用于表示资源的存在性。原生type中没有ensure属性的有:Exec,
Notify, Stage。
ruby
Puppet::Type.newtype(:custom_package) do
ensurable
...
end
Provider用create , exists? , destroy等方法来实现ensure property。
<h3 id="Parameters">Parameters</h3>
Parameters可为provider提供额外的信息,但本身不能从系统获得,也不能更新。Parameters可设定额外的context,也能覆盖provider的默认行为。比如Service支持start,stop,status,restart等参数。File资源中的source
attribute也只能作为参数,
example
source => 'http://package_repo/apache.rpm',
Puppet是无法从系统中确定source值的,source值在provider安装和更新ensure属性时就能发挥作用了。
<h3 id="默认值">默认值</h3>
默认值一般只用于parameter,而不用于property。
ruby
newparam(:replace_config) do
defaultto :no
end
<h3 id="Input Validation">Input Validation</h3>
Type API提供两个验证数据的方法:validate和newvalues。
ruby
require 'pathname'
require 'uri'
Puppet::Type.newtype(:custom_package) do
newparam(:source) do
validate do |value|
unless Pathname.new(value).absolute? ||
URI.parse(value).is_a?(URI::HTTP)
fail("Invalid source #{value}")
end
end
end
end
newvalues用于限定可选值在指定的值列表中。(newvalues方法不同于newvalue方法,newvalue方法在Puppet::Parameter::ValueCollection类中定义。)
ruby
Puppet::Type.newtype(:custom_package) do
newparam(:replace_config) do
defaultto :no
newvalues(:yes, :no)
end
end
<h3 id="munge">munge</h3>
munge方法用于转换用户输入,转换发生在与provider返回的值比较之前。比较使用的是==,因此有必要保证用户输入与系统返回值之间数据类型的一致。
ruby
newparam(:uid) do
munge do |value|
Integer(value)
end
end
validation发生在munge之前。
<h3 id="autorequire">autorequire</h3>
autorequire方法用于构建资源之间隐式的的依赖性。这样用户就可以省下很多不必要的资源的声明。
ruby
autorequire(:file) do
self[:source] if self[:source] and Pathname.new(self[:source]).absolute?
end
<h3 id="Arrays">Arrays</h3>
ruby
Puppet::Type.newtype(:custom_user) do
newproperty(:groups, :array_matching => :all) do
end
end
<h3 id="Inline Documentation">Inline Documentation</h3>
在ruby代码中使用desc方法可直接嵌入文档。
example
desc 'Whether config files should be overridden by package operations'
当前puppet环境中所有的type的文档可用下面的命令列出:
example
puppet describe --list
<h3 id="访问resource中的属性">访问resource中的属性</h3>
在newparam中是无法直接访问resource的。这一点,一开始让我非常不解,因为newparam中生成的类会是Puppet::Parameter类,在该类中能够找到:
example
attr_accessor resource
在newparam的代码中直接访问resource,却总是报NilClass的错误。
后来我总算想明白,newparam的代码其实要用来生成resource
type的类文件,在该类还没有生成的时候,去访问该类的属性或方法,当然是不行的。
有趣的是,在newparam中调用validate方法时,在validate方法的blok参数中,却是可以直接访问与该parameter关联的resource实例的。下面是我自己写的代码的例子:
ruby
newparam(:source) do
desc 'The location of archive file.'
validate do |value|
suffix_regex = ''
resource.class.supported_suffix.each { |suf| suffix_regex += "#{suf.gsub(/\./,'\.')}|" }
if value !~ /^(https?|file):\/\/.*(#{suffix_regex.chop})$/
fail "Invalid source #{value}"
end
end
end
def self.supported_suffix
['.tar.gz', '.tar.xz', '.zip', '.tgz']
end
<h2 id="Provider">Provider</h2>
<h3 id="Suitability">Suitability</h3>
confine和commands方法决定了哪个provider是有效的,defaultfor则表示在多个可用provider情况下的默认provider。
- confine
Puppet会为每个资源加载所有provider,然后通过confine来确定provider的有效性。Puppet中可用来确定provider有效性的有:facts,
files, features, boolean result of an arbitrary code block.
ruby
Puppet::Type.type(:custom_package).provide(:yum) do
confine :operatingsystem => [:redhat, :fedora, :centos, :scientific]
end
Puppet::Type.type(:puppet_config).provide(:ruby) do
# Puppet[:config] varies depending on the account running puppet.
# ~/.puppet/puppet.conf or /etc/puppet/puppet.conf
confine :exists => Puppet[:config]
end
Puppet::Type.type(:custom_package).provide(:gems) do
confine :feature => :rubygems
end
Puppet::Type.type(:agent_config).provide(:parsed) do
confine :exists => Puppet[:config]
confine :true => begin
if File.exists?(Puppet[:config])
File.readlines(Puppet[:config]).find {|line| line =~ /^\s*\[agent\]/ }
end
end
end
- commands
commands方法能够将系统的命令包装成ruby方法。
example
commands :rpm => 'rpm', :yum => 'yum'
找不到相应命令,会相当于confine失败。 用commands实现ensure的实例:
ruby
Puppet::Type.type(:custom_package).provide(:yum) do
confine :osfamily => :redhat
commands :yum => '/usr/bin/yum',
:rpm => '/bin/rpm'
def exists?
begin
rpm('-q', resource[:name])
true
rescue Puppet::ExecutionFailure => e
false
end
end
def create
package= resource[:version] ? "#{resource[:name]}-#{resource[:version]}" :
resource[:name]
yum('install', '-y', package)
end
def destroy
yum('erase', '-y', resource[:name])
end
end
- Property的实现
ruby
Puppet::Type.type(:custom_package).provide('yum') do
commands :yum => '/usr/bin/yum',
:rpm => '/bin/rpm'
def version
version = rpm('-q', resource[:name])
if version =~ /^#{Regexp.escape(resource[:name])}-(.*)/
$1
end
end
def version=(value)
yum('install', "#{resource[:name]}-#{resource[:version]}")
end
end
<h3 id="Discovery和Prefetch">Discovery和Prefetch</h3>
| Command | Provider method | Mode |
|-----------------------------------------------------|-----------------|------------|
| puppet apply | self.prefetch | management |
| puppet agent | self.prefetch | management |
| puppet resource \<type\> | self.instances | discovery |
| puppet resource \<type\> \<title\> | self.instances | discovery |
| puppet resource \<type\> \<title\> \<attr1=value1\> | self.prefetch | management |
self带头的函数只会在type初始化时执行一次,并不会每次处理资源时都执行。
self.instances返回所有资源的数组,而每个资源都会把self.instances方法中找到的对应资源的属性放在@property<sub>hash实例变量中</sub>,@property<sub>hash的key即为属性名</sub>:
ruby
def self.instances
packages = rpm('-qa','--qf','%{NAME} %{VERSION}-%{RELEASE}\n')
packages.split("\n").collect do |line|
name, version = line.split(' ', 2)
# initializes @property_hash
new( :name
=> name,
:ensure => :present,
:version => version
)
end
end
...
def exists?
@property_hash[:ensure] == :present
end
def version
@property_hash[:version]
end
self.prefetch是在puppet第一次碰到该类型的资源时被调用。一般用于cache或prefetch资源的状态。Provider若能在代价较少的情形下找出系统中所有资源的状态的话,就应考虑实现self.prefetch方法。像file属性就没有实现self.instances和self.prefetch,因为列出系统中所有的资源代价太大。prefetch方法接收一个参数,该参数为所有该provider管理的资源,一般和self.instances结合起来使用,用来设置这些资源的属性。
ruby
def self.prefetch(resources)
packages = instances
resources.keys.each do |name|
if provider = packages.find{ |pkg| pkg.name == name }
resources[name].provider = provider
end
end
end
<h2 id="feature">feature</h2>
在type中声明feature,property可以声明需要特定的feature,parameter则无需声明是否需要某feature。
ruby
Puppet::Type.newtype(:custom_package) do
...
feature :versionable, "Package manager interrogate and return software
version."
newproperty(:version, :required_features => :versionable) do
...
end
end
在provider中声明自己拥有feature:
ruby
Puppet::Type.type(:custom_package).provide('yum') do
has_feature :versionable
end
<h2 id="源码阅读">源码阅读</h2>
<h3 id="Puppet::Type.type()">Puppet::Type.type()</h3>
为了查找Puppet::Type.type()方法,颇费了番周折。Puppet::Type中有实例type方法,该方法会返回类型为字符串,也就是该类的名字。这明显不是想找的方法。Puppet::Type.type()是类方法,不是实例方法。由于Ruby可以Mixin,因此,找这个类方法真是麻烦,叫做以type为名的方法一大堆,哪个是呢?
后来想到可以查newtype方法的出处,这个名字的方法较少。后来终于搜到在Puppet::MetaType::Manager中有newtype方法的定义,找进去一看,果然是声明新的resource
type而用的,在附近也找到了名为type的方法,与Puppet::Type.type()的用法很相似。最后回到Puppet::Type类的代码中,果然找到了如下代码:
ruby
The Type class attribute accessors
class << self
# @return [String] the name of the resource type; e.g., "File"
#
attr_reader :name
# @return [Boolean] true if the type should send itself a refresh event on change.
#
attr_accessor :self_refresh
include Enumerable, Puppet::Util::ClassGen
include Puppet::MetaType::Manager
include Puppet::Util
include Puppet::Util::Logging
end
自此,真相大白。
再回过头来想,其实也不必太纠结于在写提供Provider的代码时,Puppet::Type.type(:downloaded<sub>package</sub>)的出处,只要知道该方法能得到自定义的Puppet::Type对象即可。
<h3 id="两类feature">两类feature</h3>
Puppet类中的feature与Puppet::Type中的feature是不相干的两码事情。
Puppet中的@features用于表示当前系统的特性,如augeas,selinux,libshadow,root,ssh,microsoft<sub>windows</sub>,posix等。在自定义provider时可通过confine方法来限制特性:
example
confine :feature => :rubygems
Puppet::Type中的features则只是由该类自行定义的特性名字,与系统特性无关,特性的多少与名字完全取决于Type类的定义。自定义provider中只能用has<sub>feature方法来声明自己拥有该特性</sub>:
example
has_feature :versionable
这么两个风马牛不相及的东西,由于使用了相同的名字,困惑了我好长时间。
confine方法的实现由Puppet::Confine中的test方法实现,该方法中通过require加载puppet/confine/目录下与参数':name'相同文件名的ruby文件,目前该目录下的文件有:
any,exists,false,feature,true,variable.
<h1 id="foreman <span class="tag" tag-name="foreman"><span class="smallcaps">foreman</span></span>">foreman <span class="tag" tag-name="foreman"><span class="smallcaps">foreman</span></span></h1>
<h2 id="foreman对puppet的影响">foreman对puppet的影响</h2>
foreman安装后,原来puppet master服务的8140端口被httpd服务替代。
<h1 id="Augeas <span class="tag" tag-name="augeas"><span class="smallcaps">augeas</span></span>">Augeas <span class="tag" tag-name="augeas"><span class="smallcaps">augeas</span></span></h1>
<h2 id="配置文件的路径">配置文件的路径</h2>
augtool的-r选项,或AUGEAS<sub>ROOT环境变量可改变augeas的根目录位置</sub>,然而很特别的一点:如果你不是把配置文件放在一个名字为“etc”的目录之下(或etc下子目录之下),那么在augtool中无论做什么事情都是不会对磁盘的文件有任何影响的。
可以查看如下网址查看标准配备的lens:
<http://augeas.net/stock_lenses.html>
可以看出,每个len都有相应的includes和excludes,也就意味着这些len只针对特定目录下的文件才会起作用。前面所说的etc目录问题只是这个一般问题的特殊情况。
<h2 id="添加节点">添加节点</h2>
用ins命令创建:
example
defvar hosts /files/etc/hosts
ins alias before $hosts/1/alias[1]
Augeas将label当作文本来处理,而且子节点是会按照自然数的序列来排列,因此,要在多个相同节点后添加一个新节点,有两种做法:
- 算出节点数量,新加节点为原来数量再加1(last()+1)。
example
set $hosts/1/alias[last()+1] myhost.example.com
- 使用01,02这样的标签,因为Augeas不会这样使用,新的标签必定是唯一的,不会与已经有的标签冲突。
example
ins 01 before $hosts/2
Augeas在用01添加新的节点后,内部又会转换成新的序号,一般来说01比1要排得靠前,在后续操作中依旧可以使用'01'。
在数组中使用01也是可以的,但Augeas内部会自动转换成序数,因此spec\[01\]其实与spec\[1\]的效果是一样的。对于数组,就必须使用last()函数了。
用ins命令创建节点,可以很好地控制新节点的位置,不过用set隐式创建节点更为方便。在set命令中,如果有必要,就创建相应节点。
example
set $hosts/03/ipaddr 192.168.0.1
defnode结合了set与store的功能。
example
defnode myalias $hosts/1/alias[last()+1] myhost.example.com
defnode方便接下来针对node的操作。
创建节点要根据是否有多个同名节点区别对待。如果所有节点在配置文件中都是唯一的,那很好办,直接用set命令:
example
set /files/etc/cfile/a/b/c v
a,b,c三个节点如果没有,会自动创建,如果a已经有了,b就会建在a下。
如果配置文件中已经有多个a,这时,上面的命令就会出错,因为'a'路径其实代表了多个节点的集合,无法定位到具体哪个节点,b无法创建,这时就要用predicate来限定特定的节点了:
example
set /files/etc/cfile/a[last()]/b/c v
<h2 id="Path表达式">Path表达式</h2>
<https://github.com/hercules-team/augeas/wiki/Path-expressions>
Augeas的Path表达式借鉴了XPath。Augeas的树节点有着a string label and a
string value,多个兄弟节点可以有相同label。
相同label的多个节点可以通过中括号包起来的predicate来区分,比如找出第2个alias:
example
/files/etc/hosts/1/alias[2]
为了求出这个表达式,Augeas会先根据路径构造出node set,再对node
set的节点应用谓词(Predicate),得到新的node set。node
set中的每个节点都会有position,从1开始计数。\[N\]相当于\[position() =
N\]。最后一个节点的position为last()。 还可以写出对测试node属性的谓词:
example
/files/etc/hosts/*[alias]
上面的表达式匹配至少有一个alias的host。
或者可以找出有五个以上alias的host:
example
/files/etc/hosts/*[count(alias) > 5]
谓词也可以表达式的中间使用:
example
/files/etc/hosts/*[ipaddr = "127.0.0.1"]/alias[ last() - 1 ]
找出alias为myhost.example.com的IP地址:
example
/files/etc/hosts/*/ipaddr[../alias = 'myhost.example.com']
组合谓词:
example
/files/etc/hosts/*/ipaddr[../alias = 'myhost.example.com' or ../canonical = 'myhost.example.com']
更多信息参看上面的链接。
<h2 id="Axes">Axes</h2>
通过某个轴来搜索节点的标准格式为:
example
AXIS::NAME
其中,AXIS的值可以是:self,child,descendant,descendant-or-self,parent,ancestor,root,following-sibling,preceding-sibling.
NAME的值可以是节点的label,如“alias”,或者通配符'\*'。
理解这个格式时,可以把AXIS看作是node集合,然后用NAME来根据label过滤。
标准格式很麻烦,一般使用下面的简化写法:
example
child::alias => alias
self::* => .
parent::* => ..
descendant-or-self::* => //
由此就可以明白为什么下面的命令可以打印出所有的错误信息:
example
print /augeas//error
<h2 id="puppet中的augeas">puppet中的augeas</h2>
<h3 id="不支持touch命令">不支持touch命令</h3>
puppet中使用augeas,发现不支持touch命令创建node。可用set命令,但要注意赋空字符串值:
example
set /files/etc/sudoers/Defaults[last()]/requiretty/negate ""
puppet中augeas支持命令可在changes属性的说明文档中找到。
| command | description |
|---------------------------------------|-----------------------------------------------------------------------|
| set \<PATH\> \<VALUE\> | Sets the value VALUE at loction PATH |
| setm \<PATH\> \<SUB\> \<VALUE\> | Sets multiple nodes (matching SUB relative to PATH) to VALUE |
| rm \<PATH\> | Removes the node at location PATH |
| remove \<PATH\> | Synonym for rm |
| clear \<PATH\> | Sets the node at PATH to NULL, creating it if needed |
| clearm \<PATH\> \<SUB\> | Sets multiple nodes (matching SUB relative to PATH) to NULL |
| ins \<LABEL\> (before after) \<PATH\> | Inserts an empty node LABEL either before or after PATH. |
| insert \<LABEL\> \<WHERE\> \<PATH\> | Synonym for ins |
| mv \<PATH\> \<OTHER PATH\> | Moves a node at PATH to the new location OTHER PATH |
| move \<PATH\> \<OTHER PATH\> | Synonym for mv |
| defvar \<NAME\> \<PATH\> | Sets Augeas variable \$NAME to PATH |
| defnode \<NAME\> \<PATH\> \<VALUE\> | Sets Augeas variable \$NAME to PATH, creating it with VALUE if needed |
<h3 id="onlyif属性中的match">onlyif属性中的match</h3>
augeas中的match命令会输出匹配的路径及相应的值,而puppet中的augeas在onlyif属性中使用match时,只会得到匹配的路径的结果集,并用这个结果集来做条件判断。
puppet
augeas {'unattended upgrades puppet':
context => '/files/etc/apt/apt.conf.d/50unattended-upgrades',
changes => [
"set Unattended-Upgrade/Allowed-Origins/@elem[last()+1] Puppetlabs:trusty"
],
onlyif => 'match Unattended-Upgrade/Allowed-Origins/@elem not_include "Puppetlabs:trusty"',
}
上面的resource原本是想在配置文件中如果没有"Puppetlabs:trusty"时,添加该值。然而实际运行的结果却是每次运行都会往配置文件中写入,而不管原来是否已经存在该值。究其原因,该是onlyif的条件始终为真所致,match的返回结果集中只有路径,当然始终不会include"Puppetlabs:trusty"。
解决的方法有两种:一是使用限定了值的predicate:
example
onlyif => 'match Unattended-Upgrade/Allowed-Origins/@elem[.="Puppetlabs:trusty"] size == 0',
二是先用rm命令删除原有的节点,然后逐个创建新的节点。
<h3 id="先删除后添加的模式">先删除后添加的模式</h3>
很多时候,原始的配置文件中某个节点之下已经有某些子节点配置,而这些子节点配置的值和个数都不能事先确定,这时如果针对每个子节点使用onlyif属性来判断,每个子节点都需要写一个单独的augeas资源,非常繁琐。这个时候最佳的方案是先删除该节点,然后再增加该节点,接着逐个配置子节点,这样就能用一个augeas资源来统一该节点的配置。
<h2 id="资源">资源</h2>
<https://github.com/hercules-team/augeas/wiki>
<h1 id="Nagios <span class="tag" tag-name="nagios"><span class="smallcaps">nagios</span></span>">Nagios <span class="tag" tag-name="nagios"><span class="smallcaps">nagios</span></span></h1>
<h2 id="Macro">Macro</h2>
Macro以\$开始,以\$结束。HOSTADDRESS宏会指向host对象的address属性。如下面的定义:
bash
define host{
host_name somemachine
address 10.0.0.1
check_command check-host-alive
}
define command{
command_name check-host-alive
command_line $USER1$/check_ping -H $HOSTADDRESS$
-w 3000.0,80% -c 5000.0,100% -p 5
}
命令被展开后会是下面的样子:
example
/opt/nagios/plugins/check_ping -H 10.0.0.1 -w 3000.0,80% -c 5000.0,100% -p 5
USER1一般指向nagios
plugin目录,由nagios配置文件中的resource<sub>file指令定义</sub>。
<h3 id="自定义宏">自定义宏</h3>
自定义宏就像是为Nagios添加了扩展属性,这些扩展属性以<sub>开始</sub>,名字为大写,根据类型不同,引用时的名字也不相同。
example
$_HOST
$_SERVICE
$_CONTACT
扩展MAC地址的例子如下:
bash
define host{
host_name somemachine
address 10.0.0.1
_MAC 12:12:12:12:12:12
check_command check-host-by-mac
}
define command{
command_name check-host-by-mac
command_line $USER1$/check_hostmac -H $HOSTADDRESS$ -m $_HOSTMAC$
}
<h2 id="Service">Service</h2>
Service用于描述host提供的功能,这些功能可以是传统的网络服务,如FTP服务等,也可以是像存储空间、CPU负载等信息。Service总是与host绑定在一起,通过description来标识(在某个host中,description必须唯一)。Service可定义nagios在什么时候(when),用什么方式(how)来检查,并可通知负责该Service的管理员。
<h2 id="Command">Command</h2>
Command用于定义host/service是如何检测的,还可以定义notification与事件处理机制是如何工作的。Nagios并不区分由Nagios
plugin提供的命令与自定义命令。Command的定义由两部分组成:name和command
line。命令中使用参数的格式如下:
example
command_name[!arg1][!arg2][!arg3][...]
command line可以包含宏,如\$HOSTADDRESS\$,还可以通过$ARG1$ , $ARG2$ …
\$ARG32\$等传递额外的参数,
bash
define command{
command_name check-host-alive
command_line $USER1$/check_ping -H $HOSTADDRESS$ -w $ARG1$ -c $ARG2$ -p 5
}
相应的使用该命令的host定义如下:
bash
define host{
host_name othermachine
address 10.0.0.2
check_command check-host-alive-limits!3000.0,80%!5000.0,100%
}
icinga icinga
基本概念
DB IDO (Database Icinga Data Output)
模块负责将所有配置与状态信息导入数据库。导入后的数据库可供多个其它项目使用,其中包括Icinga
Web 2。