☰
Puppet device 子命令实战指南:用 proxy agent 管理远程网络设备
2026/9/27 7:40:38 网站建设 项目流程
  • 运维
  • DevOps
  • IaC

【免费下载链接】puppet

Server automation framework and application

项目地址:https://gitcode.com/gh_mirrors/pu/puppet
点击查看免费下载

导读

puppet device是 Puppet 项目中专门用于管理远程网络设备(交换机、路由器等无法直接运行 agent 的设备)的子命令。它通过在普通 Puppet agent 上作为"代理"运行,为远程设备完成证书申请、事实收集、目录获取/应用与报告上报的完整闭环。读完本文,你将掌握 device.conf 的编写语法、puppet device全部命令行参数与退出码语义、四种工作模式(常规运行 / --facts / --resource / --apply)的用法,并从源码层面理解每个行为背后的实现原理。

本文基于当前仓库中由源码自动生成的官方手册 references/man/device.md,并对照 lib/puppet/application/device.rb、lib/puppet/util/network_device/config.rb 等源码与 spec/unit/application/device_spec.rb 测试用例展开。


一、概述:为什么要用 proxy agent 管理网络设备

puppet-device的功能一句话概括是:Retrieves catalogs from the Puppet master and applies them to remote devices——从 Puppet 主服务器获取目录(catalog),并将它们应用到远程设备上。

绝大多数网络设备(如 Cisco IOS、华为等设备)无法安装完整的 Puppet agent。因此 Puppet 设计了"代理 agent"模式:一台可以访问这些设备的普通 Puppet agent 节点充当 proxy,代表设备与 Puppet 主服务器通信。文档原文明确说明了这一架构:

Devices require a proxy Puppet agent to request certificates, collect facts, retrieve and apply catalogs, and store reports.

也就是说,proxy agent 为每台设备承担四类工作:

  1. request certificates—— 以设备的 certname 申请并维护证书(每台设备拥有独立的 SSL 目录);
  2. collect facts—— 通过设备专属的 facts terminus(network_device)从设备采集事实;
  3. retrieve and apply catalogs—— 从主服务器拉取目录并应用到设备;
  4. store reports—— 把运行报告回传给主服务器。

该子命令可以手动运行,也可以借助 cron、计划任务等工具周期性执行:

This subcommand can be run manually; or periodically using cron, a scheduled task, or a similar tool.

在源码中,lib/puppet/application/device.rb 通过app_defaults定义了该子命令的专属默认值,从侧面印证了上述架构(对应测试见 spec/unit/application/device_spec.rb 中的 "defaults the catalog_terminus setting to 'rest'" 等用例):

def app_defaults super.merge({ :catalog_terminus => :rest, # 目录从主服务器(REST)获取 :catalog_cache_terminus => :json, # 目录本地 JSON 缓存 :node_terminus => :rest, # 节点信息走 REST :facts_terminus => :network_device, # 事实从网络设备采集 }) end

注意:puppet device以:agent运行模式启动(run_mode :agent),因此它继承了 agent 的证书、目录缓存等行为。


二、USAGE:完整命令行语法

puppet device的完整用法如下(与官方手册及puppet device --help输出一致):

puppet device [-h|--help] [-v|--verbose] [-d|--debug] [-l|--logdest syslog|<file>|console] [--detailed-exitcodes] [--deviceconfig <file>] [-w|--waitforcert <seconds>] [--libdir <directory>] [-a|--apply <file>] [-f|--facts] [-r|--resource <type> [name]] [-t|--target <device>] [--user=<user>] [-V|--version]

一个最典型的最小化运行示例:

$ puppet device --target remotehost --verbose

这条命令的含义是:只对device.conf中 certname 为remotehost的那台设备执行一次完整设备运行(拉取目录、应用配置、上报报告),并开启 verbose 日志。

重要通用规则:任何在配置文件(puppet.conf)中合法的设置项都可以作为长参数传入,例如server是合法配置参数,因此可以直接写--server <servername>。


三、device.conf:设备的注册清单

3.1 文件位置与格式

被puppet device管理的设备配置在device.conf中:

  • 默认路径:$confdir/device.conf;
  • 可通过--deviceconfig <file>参数或$deviceconfig设置项覆盖。

对应设置项定义在 lib/puppet/defaults.rb(settings 分组:device):

settings.define_settings(:device, :devicedir => { :default => "$vardir/devices", :type => :directory, :mode => "0750", :owner => "service", :group => "service", :desc => "The root directory of devices' $vardir.", }, :deviceconfig => { :default => "$confdir/device.conf", :desc => "Path to the device config file for puppet device.", } )

device.conf 是一个INI 风格文件,每个设备一个 section,格式如下:

[<DEVICE_CERTNAME>] type <TYPE> url <URL> debug

各部分语义:

行含义
[DEVICE_CERTNAME]section 名即该设备的certname(证书名称)
type <TYPE>设备类型(provider),对应具体的网络设备实现
url <URL>设备访问地址,type与url的具体取值随设备类型而异
debug可选属性,开启传输层调试;仅 telnet 与 ssh 传输可用

3.2 解析器源码:语法细节与校验逻辑

lib/puppet/util/network_device/config.rb 实现了 device.conf 的解析,其parse方法揭示了若干容易被忽略的细节:

  • 注释与空行:以#开头的行和空行会被跳过;
  • section 匹配:只接受形如^\[([\w.-]+)\]$的 section 名(单词字符、点、连字符),重复定义同一设备会直接报错:"Duplicate device found at ...";
  • 指令白名单:每一行只允许type、url、debug三种指令(正则^\s*(type|url|debug)(\s+(.+)\s*)*$),其他内容一律报 "Invalid entry at ...";
  • url 校验:url指令的值会先经过URI.parse校验,非法 URL 会报 "...is an invalid url";
  • debug 开关:debug指令会把device.options[:debug]置为true(见parse_directive)。

解析结果被包装为OpenStruct,包含name(certname)、provider(type 值)、url、options等字段。

3.3 type 与 url 的语义:从设备基类看传输层解析

type的值决定了加载哪个设备实现。在 lib/puppet/util/network_device.rb 的init方法中:

def self.init(device) require "puppet/util/network_device/#{device.provider}/device" @current = Puppet::Util::NetworkDevice.const_get(device.provider.capitalize).const_get(:Device).new(device.url, device.options) rescue => detail raise detail, _("Can't load %{provider} for %{device}: %{detail}") % { provider: device.provider, device: device.name, detail: detail } end

即type直接对应puppet/util/network_device/<type>/device下的实现类,加载失败时会明确提示 "Can't load for "。

设备基类 lib/puppet/util/network_device/base.rb 则展示了url的完整解析约定:

  • url按URI解析,scheme决定传输类型(ssh、telnet 等,通过 Autoloader 加载对应transport/<scheme>实现);
  • 端口默认值:未显式指定端口时,ssh默认 22、telnet默认 23;
  • 用户名与密码从 URL 的user:password@host部分提取,用于建立传输连接。

典型的url形如ssh://user:pass@testhost或https://user:pass@testhost/some/path(后者可见于测试用例 spec/unit/application/device_spec.rb 的 device_hash 定义)。


四、OPTIONS:全部命令行参数详解

通用规则再强调一次:任何在配置文件里合法的设置项都可以作为长参数传给本命令,例如--server <servername>。

参数说明
--help, -h打印帮助信息
--verbose, -v开启 verbose 报告
--debug, -d开启完整调试输出
--logdest, -l日志去向:syslog(POSIX syslog 服务)、console或日志文件路径;支持逗号分隔多目的地(如/path/file1,console,/path/file2)。开启 debug/verbose 时默认console,否则默认syslog。以.json结尾的路径接收 JSON 结构化日志(由于日志是追加写入,文件末尾不会自动补],需手动追加以构成合法 JSON)
--detailed-exitcodes通过退出码携带事务信息,见下文"退出码语义"
--deviceconfig设备配置文件路径,默认$confdir/device.conf
--waitforcert, -w仅对尚未持有证书的目标生效,默认启用且值为 120(秒),即每 2 分钟轮询主服务器请求签署证书;设为 0 可关闭等待。适用于目标设备的初始配置
--libdir用本地目录覆盖每设备的 libdir;指定 libdir 同时会禁用 pluginsync,适合测试场景。以.jsonl结尾的路径接收 JSON Lines 结构化输出
--apply针对远程目标应用一份 manifest,必须同时指定--target
--facts显示远程目标的事实,必须同时指定--target
--resource以 Puppet 代码形式显示资源状态,功能近似于puppet resource,可按 title 过滤,必须同时指定--target
--target指定 device.conf 中的某台设备/证书,只对这台设备执行设备运行
--to_yaml以 YAML 格式输出发现的资源,适合配合 Hiera 与create_resources使用
--user以指定用户身份运行

4.1 参数校验逻辑(源码确认)

lib/puppet/application/device.rb 的main方法开头对参数组合做了强校验(对应测试见 spec/unit/application/device_spec.rb):

  • --resource未指定--target→ 报错resource command requires target;
  • --facts未指定--target→ 报错facts command requires target;
  • --apply未指定--target→ 报错missing argument: --target is required when using --apply;
  • --apply指定的 manifest 文件不存在 → 报错<file> does not exist, cannot apply;
  • --target指定的设备不在 device.conf 中 → 报错Target device / certificate '<name>' not found in <deviceconfig>;
  • device.conf 中没有任何设备 → 输出错误并exit(1)。

4.2 各参数在源码中的对应实现

  • --target、--waitforcert、--apply、--resource、--facts、--to_yaml、--libdir、--logdest、--detailed-exitcodes均在option声明中注册(见lib/puppet/application/device.rb的option(...)区块);
  • --waitforcert的值被转为整数存入options[:waitforcert],随后在setup_context中传给Puppet::SSL::StateMachine.new(waitforcert: ...)用于证书签发等待(测试 "defaults waitforcert to 0"、"uses a default value for waitforcert when --onetime and --waitforcert are not specified" 验证了默认 120 秒的行为);
  • 运行--resource/--facts/--apply三种模式时,setup方法会把日志目的地强制设为:console(因为它们本质是交互式查询)。

五、四种工作模式

puppet device依据参数组合进入四种不同模式:

5.1 常规设备运行(默认模式)

不带--resource/--facts/--apply时,对所有(或--target指定的)设备执行完整运行:

  1. 为设备创建专属目录并设置隔离的ssldir/confdir/libdir/vardir/certname(见下文"多设备隔离");
  2. 调用setup_context建立 SSL 上下文(必要时等待证书签发);
  3. 未指定--libdir时执行 pluginsync(下载设备插件);
  4. 通过Puppet::Util::NetworkDevice.init(device)初始化设备单例;
  5. 创建Puppet::Configurer并调用configurer.run(:network_device => true, :pluginsync => false)完成目录获取、应用与报告上报。

启动日志会打印目标与连接信息,形如:

starting applying configuration to device1 at ssh://testhost

5.2 --facts:查看远程设备事实

$ puppet device --target remotehost --facts

通过Puppet::Node::Facts.indirection.find从设备采集事实,并以:console渲染器输出。事实的采集实现位于 lib/puppet/indirector/facts/network_device.rb:

def find(request) result = Puppet::Node::Facts.new(request.key, Puppet::Util::NetworkDevice.current.facts) result.add_local_facts result.sanitize result end

即从当前设备单例的facts方法取得事实,再补充本地事实并做清洗处理。该 terminus 明确禁止远程请求(allow_remote_requests?返回false),且destroy/save都会抛出DevError——它只负责"从远程设备读取事实"。

5.3 --resource:查看设备资源状态

$ puppet device --target remotehost --resource user $ puppet device --target remotehost --resource user jim

用法与puppet resource类似,可指定类型与可选的 title:

  • 指定 name →Puppet::Resource.indirection.find('type/name')查找单个资源;
  • 不指定 name →Puppet::Resource.indirection.search('type/', {})搜索该类型全部资源。

输出为 Puppet 代码形式的资源声明(如user { 'jim': ensure => 'absent' })。配合--to_yaml时输出 YAML,形如:

--- user: title: ensure: absent

适用于 Hiera 数据与create_resources。注意:未指定类型时直接报错You must specify the type to display,类型不存在时报Could not find type <type>。

5.4 --apply:直接把 manifest 应用到设备

$ puppet device --target remotehost --apply site.pp

针对远程目标应用本地 manifest。从源码看,该模式会:

  • 把报告 terminus 改为:yaml(避免向服务器上报,纯本地应用);
  • 关闭目录缓存(catalog_cache_terminus = nil);
  • 将node_terminus设为:plain、catalog_terminus设为:compiler(本地编译目录);
  • 保持facts_terminus = :network_device(事实仍从设备采集);
  • 在:network_device => true覆盖下复用puppet apply的执行逻辑(Puppet::Application::Apply.new(...).run_command)。

六、退出码语义(--detailed-exitcodes)

启用--detailed-exitcodes后,退出码携带完整的事务信息:

退出码含义
1至少一台设备发生编译失败
2至少一台设备发生资源变更
4至少一台设备发生资源失败
3/5/6/7上述退出码的按位组合

例如3=1|2(既有编译失败又有资源变更),7=1|2|4(三类情况同时发生)。

源码实现(lib/puppet/application/device.rb的main结尾):每台设备的运行结果被收集后,在--detailed-exitcodes下用按位或合并:exit(returns.compact.reduce(:|))。测试用例也覆盖了这些语义,例如 "exits 6 when --detailed-exitcodes and failed run"(6 = 2|4)与 "exits 1 when --detailed-exitcodes and failed parse"(7 = 1|2|4)。

未启用--detailed-exitcodes时:任一设备返回 1 则整体退出 1,否则退出 0。


七、多设备隔离机制:每设备独立的目录与证书

这是puppet device区别于普通 agent 的关键设计。在 lib/puppet/application/device.rb 的main中,处理每台设备时会临时覆盖本地设置(并在ensure中恢复):

设置每设备取值说明
ssldir$deviceconfdir/<设备certname>/ssl设备独立的 SSL 目录
confdir$devicedir/<设备certname>设备独立的 conf 目录
libdir--libdir指定值,或$devicedir/<设备certname>/lib设备插件目录
vardir$devicedir/<设备certname>设备独立的数据目录
certname设备 section 名设备身份

其中$devicedir默认$vardir/devices,$deviceconfdir默认$confdir/devices(见 lib/puppet/defaults.rb 中的:devicedir与:deviceconfdir定义,两者目录模式均为0750)。对应测试用例 "sets ssldir relative to the global confdir"、"sets vardir to the device vardir"、"sets certname to the device certname" 等对此做了逐一验证。

两点实现细节值得注意:

  1. SSL 目录符号链接(PUP-8736 的 workaround):SSL 证书实际存放在缓存目录之外,并在$confdir/<设备>/ssl保留符号链接,防止缓存清理时误删证书;
  2. 运行后恢复全局设置:每台设备处理完(含异常路径)都会在ensure块中把libdir/vardir/confdir/ssldir/certname恢复为初始值,确保多台设备之间互不污染(测试 "resets the vardir setting after the run"、"resets the certname setting after the run" 验证了这一行为)。

八、networking 与 Provider 机制:从资源到设备的调用链

设备 provider 的基类位于 lib/puppet/provider/network_device.rb,它定义了"从设备读取资源 → 与 catalog 期望对比 → 生成变更"的抽象骨架:

  • prefetch(resources):批量预取——对每个资源,通过Puppet::Util::NetworkDevice.current(当前设备单例)或device(resource[:device_url])取得设备,再调用lookup(device, name)查询真实状态,据此为资源装配 provider(存在则ensure => :present,否则ensure => :absent);
  • create/destroy/flush:在@property_hash中维护期望状态,最终由具体 provider 实现落盘到设备;
  • instances默认为空实现,具体设备 provider 需自行实现。

结合 lib/puppet/util/network_device.rb 的单例初始化与 lib/puppet/indirector/facts/network_device.rb 的事实 terminus,整个数据流可以概括为:

puppet device └─ Puppet::Util::NetworkDevice.init(device) # 按 type 加载设备实现并建立传输 ├─ facts terminus (network_device) # 设备事实 → catalog 编译输入 └─ provider 基类 prefetch/lookup # 设备实时状态 → 资源对账

即:事实经 network_device terminus 进入目录编译,资源状态经 provider 基类的 prefetch 机制与目录期望对比,最终由设备实现把变更写回设备。


九、与 puppet agent 的关系及适用场景

  • 适用场景:网络设备(如交换机、路由器、防火墙)无法承载完整 agent,需要通过一台可达这些设备的 proxy agent 代为管理;puppet device正是这一场景的标准入口;
  • 周期性运行:文档明确指出可用 cron、计划任务等方式周期调用,实现设备的持续配置管理;
  • 证书生命周期:--waitforcert默认 120 秒的轮询机制专门服务于新设备首次接入(CSR 等待主服务器签署),签署完成后即可正常执行;
  • 测试友好:--libdir覆盖本地目录并禁用 pluginsync,便于在不依赖插件分发的情况下调试设备 provider。

十、常见问题速查

现象原因与处理
resource command requires target--resource/--facts必须与--target搭配
missing argument: --target is required when using --apply--apply必须指定--target
Target device / certificate 'xxx' not found in ...device.conf 中不存在该 certname,检查 section 名与--deviceconfig路径
Duplicate device found at ...device.conf 中重复定义了同一设备 section
Can't load <type> for <device>type值没有对应的设备实现(puppet/util/network_device/<type>/device)
退出码3/5/6/7--detailed-exitcodes下按位组合:1=编译失败、2=资源变更、4=资源失败
首次接入设备一直等待--waitforcert 120默认每 2 分钟轮询一次请求签署证书,可去主服务器侧签署;或设-w 0跳过等待

延伸阅读(仓库内)

  • 命令入口与全部模式实现:lib/puppet/application/device.rb
  • device.conf 解析器(INI 语法、校验、报错信息):lib/puppet/util/network_device/config.rb
  • 设备单例初始化与 provider 按 type 加载:lib/puppet/util/network_device.rb
  • 设备实现基类(URL/传输解析约定):lib/puppet/util/network_device/base.rb
  • 设备事实 terminus:lib/puppet/indirector/facts/network_device.rb
  • 网络设备 provider 基类:lib/puppet/provider/network_device.rb
  • 相关设置项(devicedir/deviceconfig/deviceconfdir):lib/puppet/defaults.rb
  • 单元测试(参数、隔离、退出码、四种模式的行为验证):spec/unit/application/device_spec.rb
  • 官方手册原文:references/man/device.md

本文依据仓库内 references/man/device.md 编写,相关实现与行为均对照 lib/puppet/application/device.rb 等源码及 spec/unit/application/device_spec.rb 测试用例核实。

  • 运维
  • DevOps
  • IaC

【免费下载链接】puppet

Server automation framework and application

项目地址:https://gitcode.com/gh_mirrors/pu/puppet
点击查看免费下载

相关推荐

上一篇:深入解析Graphtage:结构化数据的语义比较与合并工具
下一篇:MinIO 使用 KMS 加密 IAM 与配置数据:MINIO_KMS_SECRET_KEY 静态密钥与 KES 接入实战

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询