从 CSV 文件导入数据

想要知道更多东西吗?当你需要从表中查找某些值时,可以使用冗长的 case 语句或 selectors 实现,但更整洁的方式是使用 extlookup 函数实现。 在 puppetmaster 上可以使用 extlookup 函数查询外部的 CSV 文件,并返回匹配的数据片段。

将所有数据组织到一个单一的文件并将它从 Puppet 配置清单中分离出来, 可以使维护工作变得更简单,也便于与其他人分享:例如, 一个开发团队通过部署合适的 CSV 文件作为应用程序发布的一部分, 就可以管理 Puppet 需要知道的有关其应用程序的一切。 Puppet 只需要知道在哪里可以找到这个 CSV 文件,剩下的工作交由 extlookup 去完成。

准备工作

  1. 使用如下内容创建 /var/www/apps/common.csv 文件:

    path,/var/www/apps/%{name}
    railsversion,3
    domain,www.%{name}.com
    
  2. 使用如下内容创建 /var/www/apps/myapp.csv 文件:

    railsversion,2
    

操作步骤

  1. 在你的配置清单中添加如下代码:

    $extlookup_datadir = "/var/www/apps/"
    $extlookup_precedence = [ "%{name}", "common" ]
    
    class app( $name ) {
        $railsversion = extlookup("railsversion")
        $path = extlookup("path")
        $domain = extlookup("domain")
        notify { "App data: Path ${path}, Rails version
      ${railsversion}, domain ${domain}": }
    }
    
    class { "app": name => "myapp" }
    
  2. 运行 Puppet:

    # puppet agent --test
    info: Retrieving plugin
    info: Caching catalog for cookbook.bitfieldconsulting.com
    info: Applying configuration version '1303129760'
    notice: App data: Path /var/www/apps/myapp, Rails version 2,
    domain www.myapp.com
    notice: /Stage[main]/App/Notify[App data: Path /var/www/apps/
    myapp, Rails version 2, domain www.myapp.com]/message: defined
    'message' as 'App data: Path /var/www/apps/myapp, Rails version 2,
    domain www.myapp.com'
    notice: Finished catalog run in 0.58 seconds
    

工作原理

  1. 我们做的第一件事是定义一个变量 $extlookup_datadir,它告诉 extlookup 从哪个目录查找数据文件。你通常会在 site.pp 或者在你设置全局变量的文件中设置这个变量:

    $extlookup_datadir = "/var/www/apps/"
    
  2. 然后,我们告诉 extlookup 在哪里寻找数据文件,以及寻找的优先顺序:

    $extlookup_precedence = [ "%{name}", "common" ]
    

    这可以是任意长度的数组。当我们生成一个 extlookup 查询时,Puppet 会按顺序扫描每个文件,直到找到请求的值。文件名可以包含变量。 我们期望名为 $name 的变量已经被设置,Puppet 将会使用其值作为要查找的第一个文件名。

  3. 下一步,在 app 类中,调用 extlookup 获得一个值:

    $railsversion = extlookup("railsversion")
    

    现在 extlookup 装置查找一个 CSV 文件并从中读取数据。这个文件保存在 $extlookup_datadir 目录(在本例中是 /var/www/apps), 文件名为 %{name}.csv(在本例中是 myapp.csv)。 所以 extlookup 读取文件的完整路径是 /var/www/apps/myapp.csv, 此文件包含了 railsversion,2

    我们已经找到了所需要的值(2),所以 extlookup 将其返回。

  4. 下一个 extlookup 调用就不那么幸运了:

    $path = extlookup("path")
    

    extlookup 还是首先查找文件 myapp.csv,但是它找不到匹配 path 变量的值。 所以会查找 $extlookup_precedence 列表中的下一个文件, 即文件 common.csv:

    path,/var/www/apps/%{name}
    railsversion,3
    domain,www.%{name}.com
    

    就本例而言返回值为 /var/www/apps/myapp。

你可以看到,这允许我们在 common.csv 文件中设置一个默认值的集合, 每个应用程序都可以选择其自己的 myapp.csv 文件覆盖 common.csv 文件中的默认值。 extlookup 会依次查询列在 $extlookup_precedence 中的文件,直到其找到请求的值。 由于 myapp.csv 被列在首位,所以设置在其中的任何值都优先于文件 common.csv 中的。

更多用法

你也可以在 extlookup 调用中指定默认值,当在所有的 CSV 文件中都没有找到匹配的数据时就会使用这个默认值:

$path = extlookup("path", "/var/www/misc")

你还可以指定在查找 $extlookup_precedence 所列的文件之前首先要查找的 CSV 文件:

$path = extlookup("path", "/var/www/misc", "paths")

这首先在 paths.csv 文件中查找数据,如果没找到,将会依次查找列在 $extlookup_precedence 中的其他文件。

CSV 文件中的值也可以引用变量,正如我们曾经看到的:

domain,www.%{name}.com

你可以使用当前范围内可用的任何变量,包括 Facter 检测出的 facts 值:

domain,%{fqdn}

R.I. Pienaar 的文章 “Complex data and Puppet” 是对 extlookup 的一个很好的介绍: http://www.devco.net/archives/2009/08/31/complex_data_and_puppet.php

Jordan Sissel 曾经写过 “about configuring your whole infrastructure using extlookup”http://sysadvent.blogspot.com/2010/12/day-12-scaling-operabilitywith-truth.html

参见本书