net-connector 0.11.1 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +1 -1
- data/README.zh-CN.md +1 -1
- data/docs/VERIFICATION.md +3 -3
- data/docs/architecture.md +65 -55
- data/docs/netdisco.md +9 -5
- data/docs/netdisco.zh-CN.md +14 -10
- data/docs/templates.md +53 -0
- data/docs/usage.md +6 -1
- data/docs/usage.zh-CN.md +7 -2
- data/docs/vendors.md +50 -0
- data/lib/net/connector/concurrency/observer.rb +71 -0
- data/lib/net/connector/concurrency/pool.rb +116 -0
- data/lib/net/connector/device/base.rb +6 -2
- data/lib/net/connector/device/local_backup.rb +14 -10
- data/lib/net/connector/device/profile/builder.rb +6 -0
- data/lib/net/connector/device/profile.rb +4 -2
- data/lib/net/connector/device/remote_backup/receipt.rb +36 -0
- data/lib/net/connector/device/remote_backup/target.rb +33 -0
- data/lib/net/connector/device/remote_backup.rb +51 -0
- data/lib/net/connector/device/running_config/strategy.rb +3 -3
- data/lib/net/connector/device/running_config.rb +2 -2
- data/lib/net/connector/device/scope.rb +45 -0
- data/lib/net/connector/device/tftp/file_upload.rb +7 -9
- data/lib/net/connector/device/tftp/strategy.rb +20 -6
- data/lib/net/connector/device/topology/immediate_strategy.rb +3 -3
- data/lib/net/connector/device/topology/stages.rb +1 -1
- data/lib/net/connector/device/topology.rb +1 -1
- data/lib/net/connector/engine/command/result.rb +34 -0
- data/lib/net/connector/engine/command.rb +1 -50
- data/lib/net/connector/engine/core.rb +1 -0
- data/lib/net/connector/engine/dialogue.rb +3 -67
- data/lib/net/connector/engine/error/metadata.rb +57 -0
- data/lib/net/connector/engine/errors.rb +3 -3
- data/lib/net/connector/engine/event.rb +27 -0
- data/lib/net/connector/engine/execution.rb +2 -2
- data/lib/net/connector/engine/interaction.rb +57 -0
- data/lib/net/connector/engine/log/event.rb +2 -2
- data/lib/net/connector/engine/log/{stream.rb → redacting_writer.rb} +1 -24
- data/lib/net/connector/engine/log/transcript.rb +32 -0
- data/lib/net/connector/engine/log.rb +9 -8
- data/lib/net/connector/engine/response.rb +21 -0
- data/lib/net/connector/engine/response_reader.rb +8 -2
- data/lib/net/connector/engine/result.rb +3 -27
- data/lib/net/connector/engine/script.rb +57 -0
- data/lib/net/connector/engine/session.rb +1 -1
- data/lib/net/connector/engine/terminal/renderer.rb +186 -0
- data/lib/net/connector/engine/terminal/text.rb +35 -0
- data/lib/net/connector/engine/{transport.rb → transports.rb} +1 -21
- data/lib/net/connector/netdisco/batch.rb +5 -3
- data/lib/net/connector/netdisco/cli/backup.rb +173 -0
- data/lib/net/connector/netdisco/cli/credentials.rb +39 -0
- data/lib/net/connector/netdisco/cli.rb +3 -3
- data/lib/net/connector/netdisco/device/access.rb +31 -0
- data/lib/net/connector/netdisco/device.rb +3 -3
- data/lib/net/connector/netdisco/diagnostic.rb +7 -7
- data/lib/net/connector/netdisco/fleet.rb +32 -41
- data/lib/net/connector/netdisco/inventory/budget.rb +53 -0
- data/lib/net/connector/netdisco/inventory/cache.rb +226 -0
- data/lib/net/connector/netdisco/inventory/http.rb +255 -0
- data/lib/net/connector/netdisco/inventory/postgres.rb +236 -0
- data/lib/net/connector/netdisco/inventory.rb +47 -0
- data/lib/net/connector/netdisco/operations/batch.rb +78 -0
- data/lib/net/connector/netdisco/operations/outcome.rb +90 -0
- data/lib/net/connector/netdisco/operations.rb +13 -20
- data/lib/net/connector/netdisco/progress.rb +4 -4
- data/lib/net/connector/netdisco/report/files.rb +3 -3
- data/lib/net/connector/netdisco/report/store.rb +47 -0
- data/lib/net/connector/netdisco/report/text.rb +2 -2
- data/lib/net/connector/netdisco/report.rb +2 -2
- data/lib/net/connector/netdisco/rules.rb +5 -0
- data/lib/net/connector/netdisco/settings.rb +32 -32
- data/lib/net/connector/netdisco/tftp/archive.rb +214 -0
- data/lib/net/connector/netdisco/tftp/verifier.rb +93 -0
- data/lib/net/connector/netdisco/worker.rb +3 -3
- data/lib/net/connector/netdisco.rb +1 -1
- data/lib/net/connector/storage/{private_file.rb → atomic_file.rb} +1 -1
- data/lib/net/connector/storage/{safe_file.rb → file_reader.rb} +1 -1
- data/lib/net/connector/storage/saved_config.rb +5 -5
- data/lib/net/connector/storage.rb +2 -2
- data/lib/net/connector/templates/cisco_nxos/show_cdp_neighbors_detail.textfsm +11 -0
- data/lib/net/connector/templates/cisco_nxos/show_ip_interface_brief.textfsm +10 -0
- data/lib/net/connector/templates/cisco_nxos/show_running_config.textfsm +12 -0
- data/lib/net/connector/templates/fortinet/diagnose_lldp_rx_neighbor.textfsm +7 -0
- data/lib/net/connector/templates/index +12 -7
- data/lib/net/connector/templates/juniper/show_configuration_display_set.textfsm +6 -0
- data/lib/net/connector/templates/juniper/show_lldp_neighbors_detail.textfsm +19 -0
- data/lib/net/connector/textfsm.rb +2 -2
- data/lib/net/connector/vendor/cisco/running_config.rb +25 -0
- data/lib/net/connector/vendor/cisco/topology.rb +53 -0
- data/lib/net/connector/vendor/cisco.rb +25 -0
- data/lib/net/connector/vendor/cisco_ios/tftp.rb +40 -0
- data/lib/net/connector/vendor/cisco_ios.rb +5 -14
- data/lib/net/connector/vendor/cisco_nxos/tftp.rb +46 -0
- data/lib/net/connector/vendor/cisco_nxos/topology.rb +22 -0
- data/lib/net/connector/vendor/cisco_nxos.rb +7 -17
- data/lib/net/connector/vendor/fortinet/tftp.rb +30 -0
- data/lib/net/connector/vendor/fortinet/topology.rb +35 -0
- data/lib/net/connector/vendor/fortinet.rb +40 -0
- data/lib/net/connector/vendor/h3c/tftp.rb +36 -0
- data/lib/net/connector/vendor/h3c/topology.rb +50 -47
- data/lib/net/connector/vendor/h3c.rb +5 -5
- data/lib/net/connector/vendor/h3c_wireless.rb +2 -2
- data/lib/net/connector/vendor/hillstone/running_config.rb +8 -5
- data/lib/net/connector/vendor/hillstone/tftp.rb +54 -0
- data/lib/net/connector/vendor/hillstone/topology.rb +44 -41
- data/lib/net/connector/vendor/hillstone.rb +6 -6
- data/lib/net/connector/vendor/huawei/tftp.rb +28 -0
- data/lib/net/connector/vendor/huawei.rb +4 -4
- data/lib/net/connector/vendor/juniper/remote_backup.rb +41 -0
- data/lib/net/connector/vendor/juniper/topology.rb +40 -0
- data/lib/net/connector/vendor/juniper.rb +31 -0
- data/lib/net/connector/vendor/palo_alto/running_config.rb +70 -67
- data/lib/net/connector/vendor/palo_alto/tftp.rb +48 -0
- data/lib/net/connector/vendor/palo_alto/topology.rb +54 -51
- data/lib/net/connector/vendor/palo_alto.rb +6 -6
- data/lib/net/connector/vendor/radware/running_config.rb +11 -8
- data/lib/net/connector/vendor/radware/tftp.rb +50 -0
- data/lib/net/connector/vendor/radware/topology.rb +10 -7
- data/lib/net/connector/vendor/radware.rb +6 -6
- data/lib/net/connector/vendor/topsec.rb +27 -0
- data/lib/net/connector/vendor.rb +24 -0
- data/lib/net/connector/version.rb +1 -1
- data/lib/net/connector.rb +3 -19
- metadata +71 -42
- data/lib/net/connector/background_task.rb +0 -69
- data/lib/net/connector/device_session.rb +0 -43
- data/lib/net/connector/engine/error_metadata.rb +0 -52
- data/lib/net/connector/engine/terminal_renderer.rb +0 -184
- data/lib/net/connector/engine/terminal_text.rb +0 -33
- data/lib/net/connector/execution_pool.rb +0 -114
- data/lib/net/connector/netdisco/backup_run.rb +0 -171
- data/lib/net/connector/netdisco/client.rb +0 -281
- data/lib/net/connector/netdisco/connection.rb +0 -37
- data/lib/net/connector/netdisco/database_client.rb +0 -233
- data/lib/net/connector/netdisco/inventory_budget.rb +0 -49
- data/lib/net/connector/netdisco/inventory_cache.rb +0 -224
- data/lib/net/connector/netdisco/operation_batch.rb +0 -154
- data/lib/net/connector/netdisco/result_store.rb +0 -44
- data/lib/net/connector/netdisco/tftp_archive.rb +0 -212
- data/lib/net/connector/netdisco/tftp_verification.rb +0 -91
- data/lib/net/connector/vendor/cisco_ios/running_config.rb +0 -22
- data/lib/net/connector/vendor/cisco_ios/tftp_backup.rb +0 -41
- data/lib/net/connector/vendor/cisco_ios/topology.rb +0 -50
- data/lib/net/connector/vendor/cisco_nxos/running_config.rb +0 -13
- data/lib/net/connector/vendor/cisco_nxos/tftp_backup.rb +0 -43
- data/lib/net/connector/vendor/h3c/tftp_backup.rb +0 -33
- data/lib/net/connector/vendor/hillstone/tftp_backup.rb +0 -55
- data/lib/net/connector/vendor/huawei/tftp_backup.rb +0 -25
- data/lib/net/connector/vendor/palo_alto/tftp_backup.rb +0 -49
- data/lib/net/connector/vendor/radware/tftp_backup.rb +0 -49
- /data/lib/net/connector/templates/{cisco_cdp_neighbors_detail.textfsm → cisco/show_cdp_neighbors_detail.textfsm} +0 -0
- /data/lib/net/connector/templates/{cisco_ios_running_config_interfaces.textfsm → cisco/show_running_config.textfsm} +0 -0
- /data/lib/net/connector/templates/{cisco_ios_show_ip_interface_brief.textfsm → cisco_ios/show_ip_interface_brief.textfsm} +0 -0
- /data/lib/net/connector/templates/{h3c_interface_descriptions.textfsm → h3c/display_current_configuration.textfsm} +0 -0
- /data/lib/net/connector/templates/{h3c_lldp_local_first.textfsm → h3c/display_lldp_neighbor_information_list_local_first.textfsm} +0 -0
- /data/lib/net/connector/templates/{h3c_lldp_name_first.textfsm → h3c/display_lldp_neighbor_information_list_name_first.textfsm} +0 -0
- /data/lib/net/connector/templates/{hillstone_interface_descriptions.textfsm → hillstone/show_configuration_running.textfsm} +0 -0
- /data/lib/net/connector/templates/{hillstone_lldp_neighbors.textfsm → hillstone/show_lldp_neighbor_information.textfsm} +0 -0
- /data/lib/net/connector/templates/{palo_alto_interface_descriptions.textfsm → palo_alto/show.textfsm} +0 -0
- /data/lib/net/connector/templates/{palo_alto_lldp_neighbors.textfsm → palo_alto/show_lldp_neighbors_all.textfsm} +0 -0
- /data/lib/net/connector/templates/{radware_port_names.textfsm → radware/cfg_dump.textfsm} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b3ed9fc4eb5accaa27d54868fab18082ec076db16d0a41c46c52dcf2d700b79c
|
|
4
|
+
data.tar.gz: c89082dfd48d20024a07abca986c19320be6a385d78f95f15b01ed5e1a1c68ed
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7bbb0cd9634b952fd1dd84f9283fa30c008866f6a9494b52191927817514eb5d3662286f890782ef5d9ce3fcbdf540ff7a24d057923ba1ac22a9245b998b6429
|
|
7
|
+
data.tar.gz: 4151ff303d38cbf7ff2dad8262d60793e3aef0fc1b0170ab21fc52931a9ca9b74f45a3bcdf7574bfcab06b04ddd6e1949bae422673adb05cf25bac9ad1e9ccfb
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# 更新记录
|
|
2
2
|
|
|
3
|
+
## 0.12.0 - 2026-10-17
|
|
4
|
+
|
|
5
|
+
- 不兼容调整:模块命名空间和加载路径按领域重组,厂商类改为 `Vendor::CiscoIos` 等直接入口,清单与报告存储分别使用 `inventory:`、`report_store:` 注入,旧名称及兼容别名已移除。
|
|
6
|
+
- 模板统一采用平台目录下的完整命令名,H3C 列序变体使用文件名后缀,调用方需同步更新显式模板路径。
|
|
7
|
+
- 新增 Topsec TopOS、Fortinet FortiOS、Juniper Junos 的配置采集和本地备份,Netdisco 可按设备系统映射到对应平台。
|
|
8
|
+
- FortiOS 支持显式保存、完整配置 TFTP 导出及跨 7.6.3 的 LLDP 查询,Junos 支持已提交配置的 FTP/SCP 导出、LLDP 邻居和接口描述读取。
|
|
9
|
+
- NX-OS 增加独立的 CDP、运行配置及多 VRF IP 接口摘要模板,残缺邻居块和后续配置段不会混入已识别记录,Junos 管理信息中的端口编号也不会覆盖邻居端口。
|
|
10
|
+
- 动态确认、登录挑战及特权应答在发送前重新检查总期限,迟到应答不再发送,保留对应阶段错误和已完成步骤。
|
|
11
|
+
- 备份回执及批次结果持有独立冻结的摘要和时间副本,结果回调不能原地改写已完成备份的审计信息。
|
|
12
|
+
|
|
3
13
|
## 0.11.1 - 2026-10-17
|
|
4
14
|
|
|
5
15
|
- 允许控制器操作租约的同一线程和 Fiber 在命令结束后关闭会话;关闭期间仍拒绝回调重入、其他线程和其他 Fiber,嵌套 AP 清理失败可在释放租约前隔离连接。
|
data/README.md
CHANGED
|
@@ -31,7 +31,7 @@ The block closes the session on exit. Backups use private files and atomic repla
|
|
|
31
31
|
|
|
32
32
|
## Supported devices
|
|
33
33
|
|
|
34
|
-
H3C Comware and wireless controllers, Cisco IOS/IOS XE and NX-OS, Huawei, Hillstone StoneOS, Radware Alteon,
|
|
34
|
+
H3C Comware and wireless controllers, Cisco IOS/IOS XE and NX-OS, Huawei, Hillstone StoneOS, Radware Alteon, Palo Alto PAN-OS, Topsec TopOS, Fortinet FortiOS, and Juniper Junos OS. Capabilities vary by vendor; see the [device guide](docs/usage.md#supported-devices). Synthetic tests do not establish support for every firmware version.
|
|
35
35
|
|
|
36
36
|
## Fleet backups
|
|
37
37
|
|
data/README.zh-CN.md
CHANGED
|
@@ -31,7 +31,7 @@ end
|
|
|
31
31
|
|
|
32
32
|
## 支持的设备
|
|
33
33
|
|
|
34
|
-
H3C Comware 及无线控制器、Cisco IOS/IOS XE 与 NX-OS、华为、山石 StoneOS、Radware Alteon
|
|
34
|
+
H3C Comware 及无线控制器、Cisco IOS/IOS XE 与 NX-OS、华为、山石 StoneOS、Radware Alteon 、Palo Alto PAN-OS、天融信 TopOS、Fortinet FortiOS 和 Juniper Junos OS。各厂商能力不同,详见[设备操作指南](docs/usage.zh-CN.md#支持的设备)。合成测试不代表所有固件均已现场验证。
|
|
35
35
|
|
|
36
36
|
## 批量备份
|
|
37
37
|
|
data/docs/VERIFICATION.md
CHANGED
|
@@ -97,7 +97,7 @@ debug Logger 计数目标样本;不关闭协议检查、丢弃步骤或共享
|
|
|
97
97
|
| --- | --- | --- |
|
|
98
98
|
| 核心引擎 | `lib/net/connector/engine/**/*.rb` | 80% / 80% |
|
|
99
99
|
| 脱敏与错误处理 | `lib/net/connector/engine/errors.rb`,包含 `Redactor` | 80% / 80% |
|
|
100
|
-
| 批量并发 | `lib/net/connector/
|
|
100
|
+
| 批量并发 | `lib/net/connector/concurrency/observer.rb`、`lib/net/connector/concurrency/pool.rb`、`lib/net/connector/device/scope.rb`、`netdisco/worker.rb` | 80% / 80% |
|
|
101
101
|
|
|
102
102
|
关键组为空、任一关键文件未测量或组内没有可执行行时均失败。没有分支的组
|
|
103
103
|
不需要分支命中,但仍须通过行覆盖率及文件加载检查。
|
|
@@ -141,7 +141,7 @@ SHA-256,首次使用时从官方 GitHub Release 下载,缓存到 `tmp/tools/
|
|
|
141
141
|
|
|
142
142
|
`test/tftp_boundary_test.rb` 验证内置策略在首次 I/O 前拒绝不支持的参数组合,使用 Queue 固定 H3C 源探测后的竞争窗口,检查线程/Fiber 拒绝。上传确认后的日志、命令清理、租约清理、路径和元数据钩子失败保留回执且不重传;随机假秘密不进入新错误正文。统一回执测试核对配置来源、实际路径、设备报告等级和冻结字段;Fleet 拒绝第三方和子类提供的完成事实。既有成功/失败/echo/控制符证据用同一套合成夹具继续测试,来源和 unknown 固件范围见 `test/fixtures/tftp/README.md`。普通及最小 Bundler 安装通过本地 PTY 验证唯一的 TFTP 回执入口,没有连接真实 TFTP 服务器或上传配置。
|
|
143
143
|
|
|
144
|
-
`test/netdisco_reporting_test.rb` 覆盖 strict/selected 的状态决策矩阵、显式 CLI 退出码、统一 schema 2、Outcome 的耗时与诊断成员、Fleet/
|
|
144
|
+
`test/netdisco_reporting_test.rb` 覆盖 strict/selected 的状态决策矩阵、显式 CLI 退出码、统一 schema 2、Outcome 的耗时与诊断成员、Fleet/Report::Store 的 Report 契约,以及部分成功/回调/报告错误阻止 selected 成功。动态假秘密放入异常消息、输出、命令、source、line、phase、code 和自定义类型名,报告与私有 JSON 不得含它。受控文件/TFTP 回执阶段跨 Worker 复制仍保留,普通文件异常不能冒充设备产物。可控时钟让 UTC 倒退而单调时间前进,断言设备及批次耗时准确且无负值;没有用固定睡眠推断时间行为。
|
|
145
145
|
|
|
146
146
|
`test/backup_lock_test.rb` 通过 Queue、独立 Ruby 进程及可控单调时钟检查采集前互斥、有限等待、锁释放、线程/Fiber/回调递归、路径别名、私有权限、硬链接/FIFO 拒绝和符号链接替换。`test/backup_identity_test.rb` 验证规范地址命名、改名后的稳定身份、mtime、非普通文件拒绝和非规范文件不参与比较;稳定锁文件不作为多余备份计数。
|
|
147
147
|
|
|
@@ -232,7 +232,7 @@ BUNDLE_GEMFILE=gemfiles/json3.gemfile bundle exec ruby script/verify_json3.rb
|
|
|
232
232
|
|
|
233
233
|
`test/examples_test.rb` 验证示例进程退出码与报告策略一致、报告写入错误、统一 devices 结构、
|
|
234
234
|
TFTP 远端未核验回执以及自定义日志目录;离线复核同时支持历史 outcomes 和新 devices 报告。
|
|
235
|
-
`test/
|
|
235
|
+
`test/tftp_verifier_test.rb` 验证空文件、旧文件、符号链接、目录逃逸和 verified 策略。
|
|
236
236
|
|
|
237
237
|
## Ruby 惯用法重构回归
|
|
238
238
|
|
data/docs/architecture.md
CHANGED
|
@@ -5,24 +5,32 @@
|
|
|
5
5
|
| 层次 | 职责 | 位置 |
|
|
6
6
|
| --- | --- | --- |
|
|
7
7
|
| 会话引擎 | 登录、传输、命令、脚本及资源所有权 | `engine/` |
|
|
8
|
-
| 对话协议与响应读取 |
|
|
8
|
+
| 对话协议与响应读取 | 对话规则、交互应答与响应值分别建模;读取器管理截止时间与输出预算 | `engine/dialogue.rb`、`engine/interaction.rb`、`engine/response.rb`、`engine/response_reader.rb` |
|
|
9
9
|
| 错误与脱敏 | 错误类型和安全诊断;秘密作用域及 Expect 脱敏适配独立实现 | `engine/errors.rb`、`engine/redactor.rb` |
|
|
10
10
|
| 日志 | 事件上下文与生命周期;安全事件、格式和字节流分别实现 | `engine/log.rb`、`engine/log/` |
|
|
11
11
|
| 设备入口 | 能力组合、会话代理、通用脚本钩子 | `device/base.rb` |
|
|
12
12
|
| 设备档案 | 不可变规则与策略接口校验;Builder 负责声明 DSL | `device/profile.rb`、`device/profile/` |
|
|
13
13
|
| 配置采集与保存 | 采集策略生命周期、完整性校验、显式保存 | `device/running_config.rb`、`device/running_config/`、`device/save_config.rb` |
|
|
14
|
+
| 并发与观察 | 有限并发、后台观察线程的停止与回收 | `concurrency/pool.rb`、`concurrency/observer.rb` |
|
|
15
|
+
| 设备作用域 | 创建连接器、执行任务、关闭并分别交付值与故障 | `device/scope.rb` |
|
|
14
16
|
| 本地备份 | 采集、摘要比较、文件持久化和完成回执 | `device/local_backup.rb` |
|
|
15
17
|
| TFTP | 参数预检、上传、完成证据、目标和回执 | `device/tftp.rb`、`device/tftp/` |
|
|
16
18
|
| 拓扑 | 邻居发现、接口名称/描述、变更计划与分阶段执行 | `device/topology.rb`、`device/topology/` |
|
|
17
19
|
| 厂商差异 | 档案组装及各项能力的厂商策略 | `vendor/<厂商>.rb`、`vendor/<厂商>/` |
|
|
18
20
|
| 文件存储 | 路径锁、安全读取、私有原子写入、离线配置 | `storage.rb`、`storage/` |
|
|
19
21
|
| 解析 | TextFSM 模板选择、记录转换及异常映射 | `textfsm.rb`、`templates/` |
|
|
20
|
-
| 终端文本 | 严格 UTF-8 字节验证和终端渲染 | `engine/
|
|
21
|
-
|
|
|
22
|
+
| 终端文本 | 严格 UTF-8 字节验证和终端渲染 | `engine/terminal/text.rb`、`engine/terminal/renderer.rb` |
|
|
23
|
+
| 清单来源 | 公共字段、预算与错误;HTTP、PostgreSQL 及缓存 | `netdisco/inventory.rb`、`netdisco/inventory/` |
|
|
24
|
+
| 设备接入 | 动态凭据与批次连接策略的合并 | `netdisco/device/access.rb` |
|
|
25
|
+
| 批量编排 | 策略快照、计划校验、工作线程和报告 | `netdisco/` |
|
|
22
26
|
| 命令行入口 | 转交给 CLI,参数处理与业务流程由库负责 | `bin/net-backup` |
|
|
23
27
|
|
|
24
28
|
`Base` 引入 `RunningConfig::Capability`、`LocalBackup::Capability`、`Tftp::Capability`、`Topology::Capability`、`TextFSM::Capability` 及 `SaveConfig`。能力入口与实现共置,Base 不再重复业务包装。配置采集的临时策略绑定也由 RunningConfig 管理;备份与拓扑通过 `device.running_config` 复用同一流程。
|
|
25
29
|
|
|
30
|
+
文件名表达本文件的主要职责,领域归属通过命名空间表达。Netdisco 的清单预算与缓存位于 `inventory/`,分别为 `Inventory::Budget` 和 `Inventory::Cache`;配置操作的批次与逐台结果位于 `operations/`,分别为 `Operations::Batch` 和 `Operations::Outcome`。`Report::Store` 只持久化报告,Fleet 通过 `report_store:` 接收写入器。服务器上传核验与归档分别为 `Tftp::Verifier` 和 `Tftp::Archive`。
|
|
31
|
+
|
|
32
|
+
引擎的 `Command`、`Script`、`Interaction`、`Dialogue`、`Response`、`Command::Result`、`Result` 各有同名文件;传输事件在 `event.rb`,适配器集合在 `transports.rb`。日志的 `RedactingWriter` 与 `Transcript` 位于 `log/` 下各自的同名文件。存储边界使用 `FileReader` 表示受控读取,`AtomicFile` 表示带阶段回执的原子替换;权限和持久性约束仍由这些组件维护。
|
|
33
|
+
|
|
26
34
|
## 公开业务方法与确认范围
|
|
27
35
|
|
|
28
36
|
下表区分执行结果、业务产物和直接抛出的前置错误;调用方不能假设所有失败都在
|
|
@@ -67,9 +75,9 @@ IOS/NX-OS 清理器处理单条配置命令的响应,不把正文当成多命
|
|
|
67
75
|
|
|
68
76
|
Fleet 在规范目标校验、凭据解析及连接器构造之前加同一把锁,再向下层备份授权一次同进程、同 Fiber 的借用。借用在采集前消费,回调递归备份不能重复使用;没有全局路径缓存。路径锁在外、会话锁在内,`Base#backup` 拒绝已有会话操作中的嵌套调用。独立进程必须采用同一 flock 协议;调用方保护目录及祖先,锁不约束不合作的写入者。
|
|
69
77
|
|
|
70
|
-
`
|
|
78
|
+
`FileReader` 对一次 NOFOLLOW/NONBLOCK 打开的 FD 做 fstat 和读取,拒绝非普通文件。`SavedConfig#read/#fingerprint`、离线导出和解析复用该边界;`find` 返回当时已验证的路径,不保证调用方日后重新打开时身份不变。直接备份继续安全替换末级符号链接,Fleet/SavedConfig 则保留拒绝契约。内容不变时再核对目录项身份,避免因路径替换跳过必要写入;正常未变文件保持 mtime。
|
|
71
79
|
|
|
72
|
-
`Storage::
|
|
80
|
+
`Storage::AtomicFile.write` 统一返回 `Receipt`,执行临时文件写入、flush/fsync、rename、父目录 fsync,并跟踪 not_committed/committed/durable 和出错阶段。rename 前失败保留旧文件;之后失败保留新文件。目录 fsync 的 EINVAL/ENOSYS/ENOTSUP/EOPNOTSUPP/NotImplementedError 单独表示不支持;其他错误不能降级为成功。durable 只表示同步调用成功,未变内容不补验过去写入,断电恢复也未在本地测试中验证。
|
|
73
81
|
|
|
74
82
|
提交后的 `BackupPersistenceError` 只携带原 `Backup` 元数据和受控写入回执,Fleet 保留产物并使用已有 saved_with_error 分类。只接受库定义的具体完成错误及匹配产物类型,第三方异常的 backup 属性或自定义 WriteError 子类不作为完成证据。报告保留已提交位置,导出错误说明 committed;设备命令不会自动重放。
|
|
75
83
|
|
|
@@ -111,11 +119,11 @@ PAN-OS 使用候选配置模型。[官方提交说明](https://docs.paloaltonetw
|
|
|
111
119
|
|
|
112
120
|
`Worker` 按线程完成顺序接收终止通知,设备结果仍写入原清单槽位。任一线程中断时,调用方无需等待先创建的慢线程;创建后续线程失败时,也会停止并等待已启动的任务清理资源。普通设备故障继续转换为逐台结果,回调故障单独记录。
|
|
113
121
|
|
|
114
|
-
设备耗时由 CLOCK_MONOTONIC 度量,包含 on_start、设备任务及关闭,截止于 on_result 前。报告的总耗时覆盖目录准备和全部 worker/callback,截止于报告写入前;两者不以 UTC 时间相减。Outcome 的 duration_ms 和 Diagnostic 直接声明为 Data 成员,未测量的耗时为 nil
|
|
122
|
+
设备耗时由 CLOCK_MONOTONIC 度量,包含 on_start、设备任务及关闭,截止于 on_result 前。报告的总耗时覆盖目录准备和全部 worker/callback,截止于报告写入前;两者不以 UTC 时间相减。Outcome 的 duration_ms 和 Diagnostic 直接声明为 Data 成员,未测量的耗时为 nil。Backup 的路径、摘要及采集时间与 Outcome 的审计时间均复制冻结,构造和 `with` 更新遵守同一所有权边界;结果回调不能原地改写已保存文件的证据。`with` 替换审计时间时清除原计时,替换错误字段时清除原诊断;显式提供的新值仍经过验证。
|
|
115
123
|
|
|
116
124
|
Fleet 始终返回 Report,委托 Batch 的执行结果及严格 success?/status,单独提供 policy 和 policy_success?。默认 strict 要求非空且全部成功;selected 必须至少包含一个成功结果,其他状态只能为 filtered/sample_limit,且 callback_errors 为空、report_error 为 nil。部分成功、任何其他跳过和未知状态都阻止策略成功。
|
|
117
125
|
|
|
118
|
-
报告 summary 使用单一 schema_version: 2,包含 policy、policy_success、coverage、单调 duration_ms、逐台 diagnostic 及 report_diagnostic。coverage 仅按已尝试状态计数,失败和部分成功也算尝试。`
|
|
126
|
+
报告 summary 使用单一 schema_version: 2,包含 policy、policy_success、coverage、单调 duration_ms、逐台 diagnostic 及 report_diagnostic。coverage 仅按已尝试状态计数,失败和部分成功也算尝试。`Report::Store#write(report, directory:)` 始终接收 Report。已存文件是写入前快照;写入自身失败时,返回对象与 CLI 携带最终报告故障。`Batch#build_report` 只构造报告,不重跑任务,也不能补出未记录的总耗时。
|
|
119
127
|
|
|
120
128
|
`Report#statistics` 仅计算汇总,字段等同于 `summary.except(:devices)`,供文本与进度输出使用;完整设备明细由 JSON 输出时生成。两者不缓存结果,保留调用方持有 Batch 容器的既有语义。静默进度不读取报告。
|
|
121
129
|
|
|
@@ -123,17 +131,21 @@ Diagnostic 只保存固定词表中的码、类型、阶段和受控产物状态
|
|
|
123
131
|
|
|
124
132
|
`Planner` 先按厂商采样,再按实际 TFTP 文件名排除覆盖冲突,保留采样顺序中的首台设备。未入选设备仍标记为 `sample_limit`,只有入选后目标重名才标记为 `remote_filename_collision`。`Plan#validate!` 校验任务与清单的对应关系;调用方传入或通过 `with` 修改的计划也必须在读取凭据、创建目录及设备 I/O 前通过校验。冲突规则适用于全部厂商,包括不同地址规范化后产生相同文件名的情况。
|
|
125
133
|
|
|
126
|
-
`Settings` 保留动态秘密来源,`snapshot(mode:)` 只复制允许公开的非敏感字段,并在副作用前复用 `Configuration`、`Planner` 和 `
|
|
134
|
+
`Settings` 保留动态秘密来源,`snapshot(mode:)` 只复制允许公开的非敏感字段,并在副作用前复用 `Configuration`、`Planner` 和 `Inventory::HTTP.options` 校验。Fleet 的一次规划/执行只使用该份冻结策略;CLI 通过 `for_run` 将规划与执行绑定到同一策略。每台设备的凭据读取与策略解析分开,自定义凭据解析器给出的显式连接选项仍保留原优先级。带 `plan:` 的执行不再查询清单;以后新建的批次可以读取新策略和新的 API 凭据。
|
|
127
135
|
|
|
128
|
-
`
|
|
136
|
+
`CLI::Backup` 在创建批次目录和读取凭据前固定并验证策略。已固定的 `Settings#with_overrides` 只复制非敏感快照上的覆盖值,不重新读取环境中的策略字段;后续 `snapshot(mode:)` 继续按当前业务模式校验,离线导出不会隐式转成网络备份校验。原凭据来源仍保持动态。
|
|
129
137
|
|
|
130
|
-
`
|
|
138
|
+
`Inventory::HTTP#devices` 每次持有独立 `Inventory::Budget`,认证、分页、QueryRequired 查询共同累计正文字节和去重前记录数,并共享单调时钟 deadline。默认 HTTP 使用 `read_body`,先检查实际接收字节再追加,不信任 Content-Length。每阶段缩短原生连接/读/写超时;总期限还覆盖慢速响应头。期限观察线程只关闭本次拥有的 HTTP 连接,防止 chunked 的收尾读取拖延返回,调用结束即唤醒并 join。默认 HTTP 不做隐式 GET 重试;这一机制不进入设备命令路径。
|
|
131
139
|
|
|
132
140
|
注入的 `requester` 接收 URI 和 request。它返回后才接受长度和期限检查,不在任意用户 Ruby 回调中注入异步异常。解析和集合操作完成后也检查期限,但这不构成任意 CPU 回调的抢占保证。预算失败仅报告错误码与安全类型,没有部分清单、响应正文或底层 cause。HTTPS 的标准证书检查不变;默认允许明文 HTTP,可通过显式策略禁止。
|
|
133
141
|
|
|
134
|
-
`Settings#
|
|
142
|
+
`Settings#inventory` 构建所选清单来源,`Fleet.new(inventory: ...)` 与 `Inventory::Cache.new(inventory: ...)` 接收实现 `devices` 的来源对象。`Settings#inventory_options` 校验其公开策略。
|
|
143
|
+
|
|
144
|
+
`Inventory::Error`、`Inventory::Timeout`、`Inventory::FIELDS` 和 `Inventory.options` 属于清单领域,HTTP、PostgreSQL、缓存及设备记录只依赖这些公共契约。设备接入由 `Device::Access.resolve` 合并动态凭据、固定策略和日志路径,不创建连接,也不保存秘密。
|
|
145
|
+
|
|
146
|
+
`Settings#inventory_source` 选择 HTTP `Inventory::HTTP` 或 PostgreSQL `Inventory::Postgres`,两者只向 Fleet 提供 `devices`,不改变设备映射、计划和执行接口。数据库 SQL 与标量参数由用户配置,不内置业务表名或筛选;结果用列别名适配 `Inventory::FIELDS`,只保留这份现有字段白名单。数据库身份使用 `ND_DB_HOST/NAME/USER/PASS`,每次新建客户端时读取;端口、TLS 和超时来自 YAML 并进入不可变策略快照。
|
|
135
147
|
|
|
136
|
-
`
|
|
148
|
+
`Inventory::Postgres` 每次调用独占 PostgreSQL 连接,在只读事务中用扩展查询协议声明游标,原生解析器拒绝多语句和非查询输入。FETCH 大小及次数复用清单预算,单行模式使 libpq 不缓存整页;每行在追加前计数,额外列也消耗字节预算。驱动必须先解码单行,所以单个超大字段仍可超过 Ruby 预算的瞬时内存。总 deadline 覆盖连接和所有语句,每次 FETCH 前缩短 statement_timeout;正常完成回滚只读事务,异常关闭连接,任何失败均不交付部分清单。NOTICE、原始数据库异常及 cause 不进入日志或 CLI;稳定错误码区分连接失败、查询失败、无效清单和预算超限。SQL/参数可在 show-config 中查看,不能用于传递凭据。
|
|
137
149
|
|
|
138
150
|
数据库集成测试运行 `bundle exec rake test:postgres`,通过 `pg_config --bindir`(或 `NC_TEST_PG_BINDIR`)定位服务端工具。测试只创建临时 SCRAM 数据库和私有 Unix socket,退出时停止并删除;不会读取真实 Netdisco 凭据或连接已有服务。覆盖 SQL/参数、只读限制、真实认证失败、查询中途失败、各项预算、连接回收以及 CLI 计划。
|
|
139
151
|
|
|
@@ -155,9 +167,9 @@ Diagnostic 只保存固定词表中的码、类型、阶段和受控产物状态
|
|
|
155
167
|
任务书 NC-12(协作取消和整批 deadline)为后置可选项,本轮 **deferred**:没有新增
|
|
156
168
|
取消令牌、取消状态或“停止后不派发”的公开保证。现有 Worker 的异常 kill/join、
|
|
157
169
|
任务 ensure 和 Session 超时仍保留;任意用户回调应自行保证返回,不能承诺非合作
|
|
158
|
-
回调的硬期限。清单获取 deadline 只约束
|
|
170
|
+
回调的硬期限。清单获取 deadline 只约束 Inventory::HTTP#devices,不覆盖整个 Fleet 任务。
|
|
159
171
|
|
|
160
|
-
NC-07C 的本地服务器目录核验已接入 `
|
|
172
|
+
NC-07C 的本地服务器目录核验已接入 `Tftp::Verifier`;单设备 API 仍只报告设备回执。
|
|
161
173
|
Fleet 可把回执与本地普通文件的时间、稳定性、摘要及目录项身份关联,生成 server_verified。
|
|
162
174
|
启用历史归档并提供服务器目录时,PAN-OS 固定名可在路径锁内顺序上传、核验和归档;
|
|
163
175
|
其他场景仍拒绝同批固定名碰撞。验证失败不能重传设备命令。
|
|
@@ -225,7 +237,7 @@ Ruby 对象显式拥有资源并使用关键字参数。`Profile` 提供有限
|
|
|
225
237
|
|
|
226
238
|
## 厂商能力
|
|
227
239
|
|
|
228
|
-
`device.supports?(capability)` 读取档案与基于方法的采集命令,不建立传输连接或策略实例。接受 `:running_config`、`:save_config`、`:backup`、`:tftp_backup`、`:neighbors`、`:interface_descriptions`、`:interface_description_changes`;未知名称返回 `false`。它只表明实现了能力,不验证设备授权或固件兼容性。
|
|
240
|
+
`device.supports?(capability)` 读取档案与基于方法的采集命令,不建立传输连接或策略实例。接受 `:running_config`、`:save_config`、`:backup`、`:remote_backup`、`:tftp_backup`、`:neighbors`、`:interface_descriptions`、`:interface_description_changes`;未知名称返回 `false`。它只表明实现了能力,不验证设备授权或固件兼容性。
|
|
229
241
|
|
|
230
242
|
| 厂商 | 采集及本地备份 | 保存 | TFTP | 邻居 | 描述读取 | 描述计划及下发 |
|
|
231
243
|
| --- | --- | --- | --- | --- | --- | --- |
|
|
@@ -237,8 +249,13 @@ Ruby 对象显式拥有资源并使用关键字参数。`Profile` 提供有限
|
|
|
237
249
|
| PAN-OS | 是 | 否 | 是 | 是 | 是 | 否,候选隔离未验证 |
|
|
238
250
|
| 华为 | 是 | 是 | 是 | 否 | 否 | 否 |
|
|
239
251
|
| 山石 | 是 | 是 | 是 | 是 | 是 | 是 |
|
|
252
|
+
| Topsec TopOS | 是 | 否 | 否 | 否 | 否 | 否 |
|
|
253
|
+
| Fortinet FortiOS | 是 | 是 | 是 | 是 | 否 | 否 |
|
|
254
|
+
| Juniper Junos | 是 | 否 | 否,原生 FTP/SCP | 是 | 是 | 否,候选库提交未开放 |
|
|
240
255
|
|
|
241
|
-
`
|
|
256
|
+
Junos 的 `remote_backup` 通过 `RemoteBackup` 协调与厂商策略导出已提交配置;回执区分设备报告与远端核验。其余平台保持明确的能力声明,见[平台说明](vendors.md)。
|
|
257
|
+
|
|
258
|
+
`Profile` DSL 声明静态命令、提示符、交互和策略绑定。配置、TFTP、拓扑规则位于各自的 `vendor/<厂商>/` 下;公共业务负责校验、执行和结果语义。相同规则直接复用:NX-OS 复用 Cisco 拓扑变更流程,并绑定独立的 NX-OS 解析模板,H3C 无线继承 H3C,H3C、华为、Radware 使用公共终端渲染配置策略。目录存在不意味着必须复制一份规则,子类可只覆盖需要变化的绑定。
|
|
242
259
|
|
|
243
260
|
```mermaid
|
|
244
261
|
flowchart LR
|
|
@@ -257,7 +274,7 @@ flowchart LR
|
|
|
257
274
|
require "net/connector"
|
|
258
275
|
require "net/connector/vendor/cisco_ios"
|
|
259
276
|
|
|
260
|
-
class VariantTransfer < Net::Connector::CiscoIos::
|
|
277
|
+
class VariantTransfer < Net::Connector::Vendor::CiscoIos::Tftp
|
|
261
278
|
# 只覆盖该型号需要变化的方法,并遵守 Strategy 接口。
|
|
262
279
|
end
|
|
263
280
|
|
|
@@ -281,7 +298,7 @@ TFTP 策略的类方法 `filename(host, label: nil)` 是必需的无 I/O 命名
|
|
|
281
298
|
|
|
282
299
|
TFTP 策略必须实现 `validate_options!(target, source_file:, vrf:)`、`receipt_metadata(target, source_file:, explicit_source:)`、`resolve_source_file`、`default_path`、`remote_path`、`script` 和 `device_reported_complete?`。可继承 `Tftp::Strategy` 的公共默认值;重写上传流程时必须一并审视继承的参数约束和来源声明。预检不得访问设备,元数据只允许 configuration_kind/source_file/format/requested_path。接口缺失在 Profile 构造时失败,不再动态回退到另一套行为。
|
|
283
300
|
|
|
284
|
-
单设备 TFTP API 返回 device_reported;Fleet 的本地目录核验可提升为 server_verified。`
|
|
301
|
+
单设备 TFTP API 返回 device_reported;Fleet 的本地目录核验可提升为 server_verified。`Tftp::Archive` 在持有目标路径锁后保存旧文件,并记录其 dev、ino、size、mtime、ctime。上传时间取同一服务器目录内临时文件的 mtime,随即清理临时文件,避免文件系统时钟精度低于 Time.now 时误拒绝新上传。核验要求非空文件的新鲜时间及稳定读取;已有文件还必须发生状态变化。重新写入相同内容可以通过,未变化的旧文件即使 mtime 在未来也不能冒充新上传。预创建的服务器目标文件在上传前保持可用,成功归档后按原规则清理;未合作的外部写入者仍不受路径锁约束。
|
|
285
302
|
|
|
286
303
|
验收入口是 `script/ci`,也可用 `bundle exec rake release:check`。它检查源码、可用 Git 历史和 gem 内容中的敏感数据,执行 Ruby 与工作流 lint、完整测试,并在隔离 gem 目录及最小 Bundler 应用中安装。真实本地 PTY 烟测覆盖厂商加载、配置采集、打包模板和 CLI,不接触网络设备。初次下载依赖和工具需要联网,详见[验证文档](VERIFICATION.md)及[发布文档](RELEASING.md)。
|
|
287
304
|
|
|
@@ -303,17 +320,21 @@ TFTP 策略必须实现 `validate_options!(target, source_file:, vrf:)`、`recei
|
|
|
303
320
|
|
|
304
321
|
## 加载入口与厂商策略
|
|
305
322
|
|
|
306
|
-
公开设备 `open` 与批量任务共用 `
|
|
323
|
+
公开设备 `open` 与批量任务共用 `Device::Scope` 的关闭边界。PTY、SSH 信任快照、日志及本地文件在取得资源与登记所有权之间延后异步取消,关闭时保护回收过程;设备命令、文件读取和锁竞争仍可取消。清理保留首个故障,二次取消不能替换主错误或形成循环异常原因。
|
|
307
324
|
|
|
308
325
|
`require "net/connector"` 加载设备 API 和引擎,厂商由 `vendor_class` 按需加载。TextFSM 能力模块可预先组合,但外部 `textfsm` gem 只在实际解析时加载。仅需会话引擎时使用 `require "net/connector/engine/core"`;离线文件操作使用 `net/connector/storage`,不加载厂商。
|
|
309
326
|
|
|
310
|
-
`engine/dialogue`
|
|
327
|
+
`engine/interaction`、`engine/dialogue`、`engine/response` 分别定义交互规则、对话语法与响应值;读取循环位于 `engine/response_reader`。`engine/errors` 不加载脱敏运行时,`engine/redactor` 负责秘密作用域。Session 明确加载并持有读取器与脱敏器。
|
|
311
328
|
|
|
312
|
-
Netdisco 的 Settings、Planner、Fleet、CLI 等文件各自声明实际依赖,单独 require 后即可调用,不依赖 `netdisco.rb` 的预设加载顺序。总入口只组合 CLI 和
|
|
329
|
+
Netdisco 的 Settings、Planner、Fleet、CLI 等文件各自声明实际依赖,单独 require 后即可调用,不依赖 `netdisco.rb` 的预设加载顺序。总入口只组合 CLI 和 CLI::Backup;Batch 通过 autoload 创建 Report,避免两者循环加载。内部清单预算 `Inventory::Budget` 由 Inventory 清单适配器加载。Progress 的终端显示、Fleet 的设备执行、Report 的结果解释和 Storage 的文件持久化保持独立职责。
|
|
313
330
|
|
|
314
331
|
公共策略位于 `RunningConfig::Strategy` / `Rendered`、`Tftp::Strategy` / `FileUpload`、`Topology::Strategy` / `ImmediateStrategy`。厂商文件直接依赖公共策略,由 Profile 绑定;没有反向加载和厂商转发别名。
|
|
315
332
|
|
|
316
|
-
`
|
|
333
|
+
`Vendor` 持有平台注册表并按需加载平台类。平台本身就是连接器,例如 `Vendor::CiscoIos`,不再套一层同名 Connector。IOS 与 NX-OS 继承 `Vendor::Cisco` 的运行配置采集、CDP 拓扑和复制确认规则;各平台分别声明提示符、分页、诊断及保存命令;NX-OS 拓扑子类绑定独立的 CDP、接口配置模板。NX-OS 不再保留空的配置清理子类。H3C Wireless 继续继承 H3C 的 Comware 流程;Huawei 与 H3C 的视图和特权语义独立,不因部分命令相似而共用整份档案。
|
|
334
|
+
|
|
335
|
+
TFTP 策略的 `script` 统一执行预检并构造有界命令;平台通过私有 `transfer_command` 和 `transfer_interactions` 提供实际命令与确认应答。源文件发现、设备完成行、文件种类和服务器证据仍分别核验,不将不同平台的成功文本合并为宽松的通用匹配。模板按平台与命令组织,详见 [模板目录](templates.md)。
|
|
336
|
+
|
|
337
|
+
`Terminal::Text.utf8` 在副本上验证设备或文件的原始字节,`Terminal::Text.render` 再使用严格终端渲染。Ruby 源码默认 UTF-8 不决定 PTY 或 `File.binread` 返回的编码。非法原始字节不能因控制符擦除而通过检查;渲染损坏多字节字符时同样拒绝,错误为不含正文或 cause 的 `invalid_output_encoding`。拓扑在表头匹配和计数前复用验证,TextFSM 每次解析创建独立 Parser。日志允许转义非法字节,原始备份不转码。
|
|
317
338
|
|
|
318
339
|
### Ruby 实现与扩展边界
|
|
319
340
|
|
|
@@ -330,31 +351,18 @@ RunningConfig 的两处受控 `send` 保留,用于私有策略绑定与 protec
|
|
|
330
351
|
|
|
331
352
|
项目在开发阶段只维护当前接口,不保留旧路径转发或旧方法别名。
|
|
332
353
|
|
|
333
|
-
|
|
|
354
|
+
| 领域 | 当前类型与位置 |
|
|
334
355
|
| --- | --- |
|
|
335
|
-
|
|
|
336
|
-
|
|
|
337
|
-
|
|
|
338
|
-
|
|
|
339
|
-
|
|
|
340
|
-
|
|
|
341
|
-
|
|
|
342
|
-
|
|
|
343
|
-
|
|
|
344
|
-
|
|
|
345
|
-
| `execute`、引擎 `query` / `exchange` | `execute_command` |
|
|
346
|
-
| `run`、引擎 `execute` 脚本入口 | `execute_script` |
|
|
347
|
-
| `collect_config` | `running_config` |
|
|
348
|
-
| `tftp_backup_receipt`、三字段 `TftpBackup` | `tftp_backup` 返回 `TftpReceipt`;实际目标为 `path`;完成后错误通过 `receipt` 取回 |
|
|
349
|
-
| `PrivateFile.write_receipt` | `Storage::PrivateFile.write` 返回持久化回执 |
|
|
350
|
-
| `report_schema`、`--report-schema` | 删除版本选择;Fleet 始终返回 Report,summary 固定 schema 2 |
|
|
351
|
-
| `Batch#report`、`Device#connector` | `build_report`、`build_connector` |
|
|
352
|
-
| `Settings#credentials_for` | `device_credentials_for`;非敏感设置由批次 Policy 单独提供 |
|
|
353
|
-
| `check_response` | `validate_response!` |
|
|
354
|
-
| 拓扑 `enter_configuration` / `leave_configuration` | `enter_configuration_command` / `leave_configuration_commands` |
|
|
355
|
-
| TFTP `source_file` / `complete?` | `resolve_source_file` / `device_reported_complete?` |
|
|
356
|
-
| `command_scope` / `output_scope` | `with_command_redaction` / `with_sensitive_output` |
|
|
357
|
-
| `LegacyIndex` 和旧名称文件查找 | 只读取规范 `<IP>.txt`,无目录扫描和迁移分支 |
|
|
356
|
+
| 终端数据 | `Terminal::Text`、`Terminal::Renderer`,位于 `engine/terminal/` |
|
|
357
|
+
| 命令结果 | `Command::Result`,位于 `engine/command/result.rb`;脚本汇总仍为 `Result` |
|
|
358
|
+
| 安全诊断词表 | `Error::Metadata`,位于 `engine/error/metadata.rb` |
|
|
359
|
+
| 清单预算与缓存 | `Netdisco::Inventory::Budget/Cache`,位于 `netdisco/inventory/` |
|
|
360
|
+
| 配置操作结果 | `Netdisco::Operations::Batch/Outcome`,位于 `netdisco/operations/` |
|
|
361
|
+
| 报告存储 | `Netdisco::Report::Store`,位于 `netdisco/report/store.rb`,通过 `report_store:` 注入 |
|
|
362
|
+
| 服务器上传证据 | `Netdisco::Tftp::Verifier/Archive`,位于 `netdisco/tftp/` |
|
|
363
|
+
| 厂商平台 | `Vendor::CiscoIos` 等平台类直接继承 Base 或协议家族类;策略位于平台类下 |
|
|
364
|
+
| 文件边界 | `Storage::FileReader` 与 `Storage::AtomicFile`,分别负责受控读取与原子替换 |
|
|
365
|
+
| 终端应用 | `Netdisco::CLI::Backup/Credentials/Options`,位于 `netdisco/cli/` |
|
|
358
366
|
|
|
359
367
|
工厂方法用 `build_*` 表明返回新对象;抛错校验使用 `validate_*!`;块作用域使用明确的 `with_*`。单命令、脚本、命令文本构造和完成证据判断分别命名,避免从通用的 execute/check/complete 猜测行为。`legacy_ssh` 表示设备 SSH 协议协商选项,Netdisco QueryRequired 则是服务端 API 行为,两者均独立于本库旧版本接口。
|
|
360
368
|
|
|
@@ -386,13 +394,13 @@ RunningConfig 的两处受控 `send` 保留,用于私有策略绑定与 protec
|
|
|
386
394
|
|
|
387
395
|
批量备份只用规范化管理地址命名为 `<IP>.txt`,IPv6 的 `:` 改为 `_`。清单名称保留在结果元数据及 TFTP 文件名中。`Storage::SavedConfig` 只读取该规范路径,不扫描其他名称;缺失时 required 查找或读取抛出 ENOENT,`find(required: false)` 返回 nil。
|
|
388
396
|
|
|
389
|
-
新建规范文件时报告 created,之后只与同一路径的内容比较。设备改名不会改变身份或基线,其他名称文件不会被读取、迁移或覆盖。Fleet 在凭据解析和连接前检查规范目标,拒绝符号链接和非普通文件;持有路径锁直至备份结束。`
|
|
397
|
+
新建规范文件时报告 created,之后只与同一路径的内容比较。设备改名不会改变身份或基线,其他名称文件不会被读取、迁移或覆盖。Fleet 在凭据解析和连接前检查规范目标,拒绝符号链接和非普通文件;持有路径锁直至备份结束。`FileReader` 在同一 FD 上完成检查和读取;它与 flock 均不能阻止不合作的外部写入者,目录保护仍由调用方负责。
|
|
390
398
|
|
|
391
399
|
## 日志组件与事件
|
|
392
400
|
|
|
393
401
|
`Log` 管理日志资源、级别和上下文;`Log::Event` 冻结已脱敏的标量字段;`Log::Formatter` 提供标准 Logger 文本格式;`Log::Transcript` 以行组织设备回显,`Log::RedactingWriter` 将分片直接交给 Expect::Redactor。日志模块不再实现另一套秘密匹配算法。
|
|
394
402
|
|
|
395
|
-
连接、命令和操作失败统一经过 `Log#log_failure`。错误类型、错误码和阶段由 `
|
|
403
|
+
连接、命令和操作失败统一经过 `Log#log_failure`。错误类型、错误码和阶段由 `Error::Metadata` 的固定词表过滤,Netdisco 报告复用同一规则;未知错误码不输出,未知阶段使用引擎当前阶段,未知类型归为 StandardError。异常正文仍先由会话脱敏,防止配置钩子把未登记的配置放进错误元数据后进入日志。
|
|
396
404
|
|
|
397
405
|
操作后处理无论抛出异常还是返回失败 Result,都在敏感作用域退出前归一化错误,再记录完成事件;Result 的已完成步骤及配置内容保持原样。最终处理继承实际执行的命令及交互敏感性,包括准备钩子、替换命令和追加查询;只累计标记,不长期保留秘密,也不影响后续普通命令的日志。
|
|
398
406
|
|
|
@@ -408,7 +416,7 @@ RunningConfig 的两处受控 `send` 保留,用于私有策略绑定与 protec
|
|
|
408
416
|
|
|
409
417
|
注入的 logger 由调用方持有;连接器不修改级别、formatter、progname,也不关闭它。每次写入同时检查配置与 logger 当前级别。消息对象支持 to_s/inspect 和安全 to_h,应用可自行输出 JSON。自有文本日志使用毫秒时间及逐行事件;raw 文件只写经过敏感保护的字节。上下文退出前先收尾渲染与脱敏缓冲,避免上一命令尾部被标成下一条命令。
|
|
410
418
|
|
|
411
|
-
|
|
419
|
+
终端进度显示由 Progress 单独管理:终端 write/flush 的普通故障会停用后续显示,并只保留固定词表内的错误类型,不携带原始异常。心跳照常回收,设备任务、events.jsonl 与报告持久化继续进行;CLI::Backup 将显示故障合并为一次批次 callback_errors。若首次故障发生在报告保存后的最终显示阶段,仅补写一次报告诊断,最终 JSON 与退出码采用更新后的策略结果;已有报告错误保持优先,不重放设备备份或事件。
|
|
412
420
|
|
|
413
421
|
`log_file` 使用 NOFOLLOW/NONBLOCK 打开,再对同一 FD 检查普通文件类型,随后才修改权限或写入。FIFO、设备文件和目录不能用作日志文件;应用拥有的输出流通过 `logger` 接入。日志打开先于登录,不能依赖登录超时为文件打开提供期限。
|
|
414
422
|
|
|
@@ -416,14 +424,14 @@ RunningConfig 的两处受控 `send` 保留,用于私有策略绑定与 protec
|
|
|
416
424
|
|
|
417
425
|
应用代码优先使用 `Net::Connector.open/build`、`Base` 的公开设备方法、`Command`、`Script`、结果对象,以及 `Netdisco::Fleet`。厂商扩展使用 `Profile` DSL 和文档中列出的策略接口;`Profile::Builder`、`Session` 的状态字段、工作线程调度及解析辅助方法属于内部实现。扩展直接加载当前设备模块或厂商目录下的类。项目仍处于 0.x,公开契约的变更会在更新记录中说明。
|
|
418
426
|
|
|
419
|
-
gem 不依赖 Rails,也不自动创建数据库模型或管理应用的连接池。`logger: Rails.logger` 由应用持有,连接器写入安全事件对象,不修改或关闭它。数据库报告通过 `
|
|
427
|
+
gem 不依赖 Rails,也不自动创建数据库模型或管理应用的连接池。`logger: Rails.logger` 由应用持有,连接器写入安全事件对象,不修改或关闭它。数据库报告通过 `Report::Store::Database` 注入仓储,写报告发生在调用线程中;逐设备凭据解析、连接器工厂和回调则运行在工作线程中。
|
|
420
428
|
|
|
421
429
|
在 Rails 内调用涉及模型、自动加载或应用状态的线程代码时,应由应用用 `Rails.application.executor.wrap` 包住相应调用。仅在外层包住 `fleet.backup_all` 不会覆盖子线程。例如,凭据解析器可以写为:
|
|
422
430
|
|
|
423
431
|
```ruby
|
|
424
432
|
credentials = lambda do |device|
|
|
425
433
|
Rails.application.executor.wrap do
|
|
426
|
-
DeviceCredential.for_host(device.host).
|
|
434
|
+
DeviceCredential.for_host(device.host).connection_options
|
|
427
435
|
end
|
|
428
436
|
end
|
|
429
437
|
```
|
|
@@ -432,10 +440,12 @@ end
|
|
|
432
440
|
|
|
433
441
|
## 公共并发、配置批次与清单缓存
|
|
434
442
|
|
|
435
|
-
`
|
|
443
|
+
`Concurrency::Pool` 只持有线程、启动闸门和完成事件,按输入顺序交付块结果。普通设备失败如何转成结果由业务适配负责;创建并登记线程时延迟异步中断,登记完成后恢复,启动失败不执行任何设备块。工作线程捕获异常并由调用线程同步传播,避免宿主全局线程策略影响无关线程。原 `Netdisco::Worker` 保留备份计时、结果槽位和通知适配,不再自行管理线程。
|
|
444
|
+
|
|
445
|
+
`Device::Scope` 持有单台任务连接器,分别交付业务值与普通故障,收尾不覆盖先前错误或中断。`Netdisco::Operations` 为配置脚本与接口描述同步、规划/应用提供全批预检、固定策略、动态凭据和安全摘要;它保留领域 `Result`、计划和完成步骤,使用独立 `Operations::Batch`,不借用备份路径或上传状态。应用审批计划必须走原拓扑重验、变更、回读、保存流程;有限并发不代表跨设备事务或自动重试安全。
|
|
436
446
|
|
|
437
|
-
`
|
|
447
|
+
`Device::Access` 为备份与配置操作统一解析逐设备连接设置:每台设备重新读取凭据,自定义设置覆盖本批固定连接策略,批次日志目录决定日志路径。它不缓存凭据或创建连接;缺少凭据返回 nil,调用入口保留各自的结果分类。`CLI::Credentials` 负责清单客户端与凭据来源的组装,两者不共享设备会话生命周期。
|
|
438
448
|
|
|
439
|
-
`Settings#
|
|
449
|
+
`Settings#inventory` 为原始清单适配器包裹 `Inventory::Cache`,默认三天有效。缓存仅保存完整白名单 rows,Rules 和重复地址判定每次重做。身份、SQL 及绑定参数只参与摘要分区,不写入文件;凭据缺失仍在缓存读取前拒绝。过期刷新在有界、按身份的跨进程文件锁内完成,成功后原子替换;失败使用原时间的已验证历史,成功空清单替换旧值。最新查询成功与本地缓存持久化成功是两个事实,不能因写盘失败回退旧数据或重复查询。强刷跳过有效期,不跳过身份、限额、文件校验和失败回退边界。
|
|
440
450
|
|
|
441
|
-
后台心跳和 HTTP 超时观察使用内部 `
|
|
451
|
+
后台心跳和 HTTP 超时观察使用内部 `Concurrency::Observer` 作用域,前台保留主业务值和原始故障;观察线程的异常同步交付所有者,不受宿主全局线程异常策略影响。创建至登记期间延后中断,停止和等待期间保证线程回收;心跳普通故障转换为显示诊断,正常 HTTP 请求的未知观察故障仍传播。
|
data/docs/netdisco.md
CHANGED
|
@@ -59,7 +59,7 @@ Expired inventory refreshes automatically. A remote inventory failure falls back
|
|
|
59
59
|
|
|
60
60
|
An empty or malformed cache file is a cache miss and triggers a remote query. It cannot supply fallback history if that query fails.
|
|
61
61
|
|
|
62
|
-
Use `net-backup --refresh-inventory`, `fleet.devices(force_refresh: true)`, or `fleet.plan_backup(force_refresh: true)` to bypass freshness. TFTP planning accepts the same keyword. A forced refresh also falls back to valid history if the remote request fails. `cache_enabled: false` disables caching. Injected
|
|
62
|
+
Use `net-backup --refresh-inventory`, `fleet.devices(force_refresh: true)`, or `fleet.plan_backup(force_refresh: true)` to bypass freshness. TFTP planning accepts the same keyword. A forced refresh also falls back to valid history if the remote request fails. `cache_enabled: false` disables caching. Injected inventory sources stay uncached unless explicitly wrapped in `Netdisco::Inventory::Cache`; shared wrapper status describes the latest call, so synchronize concurrent access to the same instance. Cache locks bound waiting and coalesce ordinary expired-cache refreshes across processes; independently requested forced refreshes still query the source.
|
|
63
63
|
|
|
64
64
|
## CLI planning and execution
|
|
65
65
|
|
|
@@ -74,6 +74,10 @@ net-backup --config config.yml --export 192.0.2.7 --output ./exports/device.cfg
|
|
|
74
74
|
|
|
75
75
|
The installed command is `net-backup`; source checkouts use `bundle exec bin/net-backup`. `--show-config` validates public settings without querying inventory. `--plan` queries and validates inventory without connecting devices. `--host` selects one address and fails if absent. Local CLI backups select all ready devices by default; TFTP selects at most five per vendor unless `--all` is given. `--limit-per-vendor` accepts 1 through 5.
|
|
76
76
|
|
|
77
|
+
Here `vendor` is the connector platform key, such as `cisco_ios` or `cisco_nxos`, rather than the manufacturer. Filtering and sampling use that key: a limit of five can select five IOS devices and five NX-OS devices. `source_vendor` retains the original inventory vendor label.
|
|
78
|
+
|
|
79
|
+
Interactive batch examples use `CLI::Backup`; `CLI::Credentials.resolve` supplies the inventory source and per-device credential resolver, while `CLI::Options` parses arguments and configuration overrides. These components live under `netdisco/cli/`.
|
|
80
|
+
|
|
77
81
|
`--export IP` reads an existing canonical `<IP>.txt` file offline. It writes original bytes to stdout, or atomically writes a private file with `--output`. It does not require inventory or device credentials. Hostname-prefixed batch-example files are not searched by this command.
|
|
78
82
|
|
|
79
83
|
Plans and results are JSON. Exit codes:
|
|
@@ -110,7 +114,7 @@ Fleet returns `Netdisco::Report`, delegating raw execution fields to `report.bat
|
|
|
110
114
|
|
|
111
115
|
Local backups compare SHA-256. `on_change:` fires for created or changed artifacts; `on_start:` and `on_result:` observe attempted tasks. Callback faults appear in `callback_errors`. Saved artifacts with later errors remain `saved_with_error`; confirmed uploads with later errors remain `reported_with_error`. Neither result permits automatic replay.
|
|
112
116
|
|
|
113
|
-
`
|
|
117
|
+
`Report::Store::Json` writes private JSON by default. Use `Report::Store::Database.new(repository: YourModel)` with a `create!(attributes)` repository, or `report_store: nil` to persist yourself. Custom stores receive `write(report, directory:)`. Report errors retain known committed locations and prevent success.
|
|
114
118
|
|
|
115
119
|
## Configuration batches and interface changes
|
|
116
120
|
|
|
@@ -132,13 +136,13 @@ Scripts accept `Script`, command arrays or multiline text. The full batch is par
|
|
|
132
136
|
|
|
133
137
|
Interface application calls the existing topology operation, retaining evidence revalidation, configuration readback and persistence confirmation. It does not execute an approved plan as an ordinary script. Both write operations require `confirmed: true`, and never automatically retry commands. Each task owns and closes its connector. Ordinary failures remain per-device outcomes; `Interrupt` stops and joins all owned workers. Confirmed work is not rolled back across devices.
|
|
134
138
|
|
|
135
|
-
`
|
|
139
|
+
`Operations::Batch` is separate from backup reports. `outcomes` retain the original `Result` or plan, completed steps and the first failure; `:partial` preserves work followed by an error, and missing credentials prevent success. `plans` selects only fully successful planning results. `to_h` includes safe diagnostics and counts, excluding commands, outputs, credentials and evidence. `on_start` and `on_result` run on workers and must be thread safe; ordinary callback faults are recorded without repeating device operations. Logging uses the configured `ssh.log_directory`.
|
|
136
140
|
|
|
137
141
|
`sync_interface_descriptions` is the direct update entry: one request and one connection per device, from discovery through readback and save. Matching descriptions cause no writes or saves; a no-op does not confirm an earlier save. The default format is `To_<peer name>_<interface abbreviation>`; formatting options and blocks remain backend choices. Separate preview/approval workflows remain available through `plan_interface_descriptions` and `apply_interface_descriptions(plans: planned.plans, confirmed: true)`.
|
|
138
142
|
|
|
139
143
|
Each device publishes one immutable outcome after execution and connection cleanup. Ordinary credential, connection, execution and cleanup failures affect that device while active and queued siblings continue. Once scheduling completes, `summary` and `to_h[:summary]` report `total`, `succeeded` and `failed`, with total = succeeded + failed. Total counts the devices requested and scheduled in this batch; partial completion and missing credentials count as failures and also appear in `partial` and `missing_credentials`. `callback_errors` counts notification faults separately without changing device outcomes. Empty batches report zero counts and `no_devices`. The library returns the report; callers choose terminal output or JSON export. Whole-batch approval validation and interruption retain their existing boundaries, and completed device changes cannot be rolled back.
|
|
140
144
|
|
|
141
|
-
For other independent tasks, load `net/connector/
|
|
145
|
+
For other independent tasks, load `net/connector/concurrency/pool` and use `Net::Connector::Concurrency::Pool.new(concurrency: 4).map(items) { |item| ... }`. Results preserve input order, all threads must start before any block runs, and uncaught exceptions stop the pool and propagate to its caller. Business code decides which ordinary errors become per-task results.
|
|
142
146
|
|
|
143
147
|
## PostgreSQL inventory
|
|
144
148
|
|
|
@@ -179,7 +183,7 @@ Default budgets cover authentication, pagination, fallback queries, or database
|
|
|
179
183
|
|
|
180
184
|
HTTP counts actual chunks and closes on excess. Injected `requester:` callbacks are checked only after returning; their blocking and memory belong to the caller. PostgreSQL counts column names and values, including discarded fields, after libpq decodes each row; a huge field may still consume driver memory before the check. Connection, query, and FETCH share the deadline and use database statement timeouts.
|
|
181
185
|
|
|
182
|
-
`Settings#snapshot(mode:)` freezes public policy before side effects. CLI planning and execution share it; later calls can read new settings. Credentials remain dynamic per task. `Settings.new.for_run(mode: :backup)` shares policy across API calls; non-sensitive overrides preserve an existing snapshot. A custom `credentials:` resolver can supply per-device connection options, taking precedence over defaults. Injected
|
|
186
|
+
`Settings#snapshot(mode:)` freezes public policy before side effects. CLI planning and execution share it; later calls can read new settings. Credentials remain dynamic per task. `Settings.new.for_run(mode: :backup)` shares policy across API calls; non-sensitive overrides preserve an existing snapshot. A custom `credentials:` resolver can supply per-device connection options, taking precedence over defaults. Injected inventory sources remain caller-owned.
|
|
183
187
|
|
|
184
188
|
Snapshot backup, cache, log, TFTP verification, SSH known-hosts and explicit PostgreSQL CA certificate paths resolve against the working directory captured when the snapshot is created, including default paths and later relative overrides. Paths beginning with `~/` and the path `~` use the home directory captured by that snapshot. PostgreSQL CA paths retain libpq's literal path semantics without tilde expansion; `sslrootcert: system` keeps its system trust-store meaning, while `./system` names a file. Live settings continue to resolve paths against the current working directory and home directory.
|
|
185
189
|
|
data/docs/netdisco.zh-CN.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
`Net::Connector::Netdisco` 读取并验证完整清单,再将支持的记录映射到连接器,使用有上限的工作线程执行备份。Netdisco 只提供清单字段;设备凭据来自环境变量或调用方提供的解析器。清单会在连接任何设备前完成校验;不支持、被过滤、重复、缺少凭据、失败,以及保存成功但关闭失败的结果分别保留。
|
|
8
8
|
|
|
9
|
-
每次 `
|
|
9
|
+
每次 `Inventory::HTTP#devices` 默认限制单响应 16 MiB、累计响应 128 MiB、去重前 100,000 条记录、10,000 页和 300 秒总期限。认证、分页及兼容查询共用这些预算;默认 HTTP 客户端逐块计数,超限会关闭连接并抛出带稳定 `code` 的 `Inventory::Error`,Fleet 不会执行半份清单。这些默认值是可调整的设计起点,不是实测容量。可注入 `requester: ->(uri, request)`;该回调只能在回调返回后检查正文和期限,回调自身的阻塞及内存用量由注入方控制。
|
|
10
10
|
|
|
11
11
|
推荐使用 HTTPS,标准证书验证保持开启。`allow_insecure_http` 默认为 `true`;设为 `false` 可在发请求前拒绝 HTTP,YAML 中对应 `netdisco.allow_insecure_http: false`。HTTP 会明文传输登录凭据和 API key,迁移时应先提供可验证的 HTTPS 端点。
|
|
12
12
|
|
|
@@ -14,11 +14,11 @@
|
|
|
14
14
|
|
|
15
15
|
本地 `backup(path:)` 用 SHA-256 比较新旧配置,`backup.change` 返回 `:created`、`:changed` 或 `:unchanged`;内容未变且权限、文件身份正常时保留修改时间。这不补验历史写入的断电持久性。`backup_all` 的 `on_change:` 仅在新建或更改文件保存后触发;`on_start:` 和 `on_result:` 观察每台已尝试设备。回调异常记录在 `batch.callback_errors`,不丢弃设备结果。每项结果包含开始、结束和耗时。TFTP 无法比较服务器文件,因此没有 `change`,也不触发变更通知。
|
|
16
16
|
|
|
17
|
-
每批默认由 `
|
|
17
|
+
每批默认由 `Report::Store::Json` 写入私有 JSON 报告,路径见 `batch.report_location`。调用方如有数据库仓储,可传 `Report::Store::Database.new(repository: YourModel)`;仓储需实现 `create!(attributes)`。`report_store: nil` 表示由调用方自行持久化。报告失败保留在 `batch.report_error`,同时使 `batch.success?` 为假。若报告已替换但目录同步失败,仍保留位置;离线 `--export --output` 遇到同类错误返回 2,并说明文件已经提交。
|
|
18
18
|
|
|
19
19
|
Fleet 统一返回 `Netdisco::Report`,JSON 的 `schema_version` 固定为 `2`。报告包含 `policy`、`policy_success`、清单覆盖和受控诊断;`success?` / `status` 表示严格完成情况,`policy_success?` 表示所选成功策略。任务耗时使用单调时钟,UTC 开始/结束时间独立保留。`report.batch` 是原始执行快照;手工构造的 Batch 可用 `batch.build_report(policy: :selected)` 生成报告,不会再次执行设备或重写文件。
|
|
20
20
|
|
|
21
|
-
`success_policy: :selected` 要求至少一台设备成功,其他记录只因 `filtered` 或 `sample_limit` 跳过,而且没有部分成功、回调或报告错误。缺少凭据、重复地址、无效地址、未知厂商、目标冲突和未知状态均会阻止成功。`coverage.complete` 只表示每条清单记录都已尝试任务;失败任务也计入尝试,不能据此判断配置已保存。自定义 `
|
|
21
|
+
`success_policy: :selected` 要求至少一台设备成功,其他记录只因 `filtered` 或 `sample_limit` 跳过,而且没有部分成功、回调或报告错误。缺少凭据、重复地址、无效地址、未知厂商、目标冲突和未知状态均会阻止成功。`coverage.complete` 只表示每条清单记录都已尝试任务;失败任务也计入尝试,不能据此判断配置已保存。自定义 `Report::Store#write(report, directory:)` 始终接收 Report,并通过 `summary` 获取统一 JSON 结构。
|
|
22
22
|
|
|
23
23
|
外部构造的计划也必须把同一管理地址的全部条目标记为 `duplicate_host` 并跳过,不能通过采样恢复其中一条的执行资格;IPv6 的等价写法视为同一地址。只需汇总时使用 `report.statistics`,它返回 `summary` 除 `devices` 外的字段,不生成设备明细,也不缓存调用方持有的批次容器。
|
|
24
24
|
|
|
@@ -132,6 +132,8 @@ SQL、参数和来源也可分别通过 `--query SQL`、`--query-params JSON`、
|
|
|
132
132
|
|
|
133
133
|
`--plan` 只拉取并验证清单;`--host` 选择一个管理地址;`--tftp` 默认每厂商最多选择五台,`--all` 选择所有就绪设备。本地备份默认选择所有就绪设备,可用 `--limit-per-vendor` 限制。`--show-config` 只输出有效的非敏感设置,不访问 Netdisco。CLI 会拒绝未知 YAML 字段、Ruby 对象标签及配置中的凭据。`--export IP` 只离线读取规范化管理地址对应的 `<IP>.txt`;默认原样写到标准输出,指定 `--output` 后以 `0600` 权限原子写文件。导出的配置仍是敏感数据。
|
|
134
134
|
|
|
135
|
+
这里的 `vendor` 表示连接器平台标识,如 `cisco_ios`、`cisco_nxos`,并非制造商;筛选和采样均按该标识分组。因此限制五台时,IOS 与 NX-OS 可各选五台。`source_vendor` 保留清单中的原始厂商标签。
|
|
136
|
+
|
|
135
137
|
CLI 的计划与批次摘要使用 JSON。默认 `--success-policy strict` 使用严格规则:非空清单且全部成功、回调及报告正常时为 `0`;空清单或有跳过、部分成功、失败时为 `1`;清单或配置错误为 `2`。`--host` 未在清单中找到也返回 `2`。由于其他清单记录会标记为过滤,默认单主机备份成功时批次退出码仍可能是 `1`;应查看 JSON 中的 `succeeded`、`skipped` 和逐台 `status`。
|
|
136
138
|
|
|
137
139
|
显式使用 `--success-policy selected` 后,CLI 按上述 selected 规则决定退出码,保留严格的 `status: incomplete` 与跳过计数,另列 `policy_success`。例如 `net-backup --config config.yml --host 192.0.2.7 --success-policy selected`。成功策略由本次 CLI/API 参数指定,不改变已批准的清单选择,也不触发重试。
|
|
@@ -177,7 +179,7 @@ ssh:
|
|
|
177
179
|
|
|
178
180
|
`Fleet` 每次规划或执行前通过 `Settings#snapshot(mode:)` 固定非敏感设置,包括筛选规则、目录、并发、协议、主机密钥、日志、TFTP 参数和清单预算。执行中修改 ENV 不改变当批策略;再次调用会读取新值。CLI 一次调用的规划与执行共用策略,优先级为 CLI > 常用环境变量 > YAML > 默认值。`Settings#validate!(mode:)` 复用连接配置及 Planner 的枚举和范围规则;`--show-config` 会拒绝非法设置,`--export` 只验证离线目录,不要求清单地址或认证。
|
|
179
181
|
|
|
180
|
-
每台任务开始时仍读取设备凭据,`Settings.from_file` 也保留轮换能力。纯策略快照不保存密码、API key 或凭据解析器。需要让多次 API 调用共用策略时,可传 `Settings.new.for_run(mode: :backup)`。自定义 `credentials:` 解析器仍可逐设备返回连接设置,它显式给出的选项优先于批次默认值,由调用方负责一致性;注入的 `
|
|
182
|
+
每台任务开始时仍读取设备凭据,`Settings.from_file` 也保留轮换能力。纯策略快照不保存密码、API key 或凭据解析器。需要让多次 API 调用共用策略时,可传 `Settings.new.for_run(mode: :backup)`。自定义 `credentials:` 解析器仍可逐设备返回连接设置,它显式给出的选项优先于批次默认值,由调用方负责一致性;注入的 `inventory:` 生命周期也由调用方管理。传入 `plan:` 的执行不会重新拉取或筛选已批准清单。`fleet.devices` 可在不连接设备时检查映射。
|
|
181
183
|
|
|
182
184
|
快照中的备份、缓存、日志、TFTP 核验目录、SSH known-hosts 路径及显式 PostgreSQL CA 证书路径,以创建快照时的工作目录为基准,默认路径和后续相对路径覆盖也沿用这一基准。`~/` 开头的路径及 `~` 使用快照创建时的主目录。PostgreSQL CA 路径保留 libpq 的字面路径语义,不展开波浪号;`sslrootcert: system` 仍表示系统信任库,`./system` 则表示文件。未固定的活设置仍按调用时的当前工作目录和主目录解析路径。
|
|
183
185
|
|
|
@@ -231,15 +233,17 @@ require "net/connector/netdisco"
|
|
|
231
233
|
netdisco = Net::Connector::Netdisco
|
|
232
234
|
options = netdisco::CLI::Options.parse(argv: ["--concurrency", "10"])
|
|
233
235
|
settings = netdisco::CLI::Options.settings(options)
|
|
234
|
-
|
|
236
|
+
inventory, credentials = netdisco::CLI::Credentials.resolve(settings)
|
|
235
237
|
directory = Net::Connector::Storage::BatchDirectory.create("./backups")
|
|
236
238
|
# 获得 report 和 plan 后:
|
|
237
239
|
# report = netdisco::Report::Files.write(report, directory: directory, plan: plan, concurrency: 10)
|
|
238
240
|
```
|
|
239
241
|
|
|
240
|
-
`CLI::Options.parse` 接受 `argv/input/output/error/program`,不修改传入参数数组;帮助通过返回值 `:help` 通知调用方,非法输入抛出 `ArgumentError`。`
|
|
242
|
+
`CLI::Options.parse` 接受 `argv/input/output/error/program`,不修改传入参数数组;帮助通过返回值 `:help` 通知调用方,非法输入抛出 `ArgumentError`。`CLI::Credentials.resolve` 接受 `input:`,标准输入凭据仅消费一行,RUN 确认由脚本编排负责。模块不加载 `.env` 或切换目录。
|
|
243
|
+
|
|
244
|
+
批量示例由 `Netdisco::CLI::Backup` 统一编排,`CLI::Options.settings` 为示例和正式 CLI 共用配置覆盖入口。
|
|
241
245
|
|
|
242
|
-
|
|
246
|
+
终端入口按职责放在 `cli/`:`CLI::Backup` 编排批量备份,`CLI::Credentials.resolve` 解析凭据来源,`CLI::Options` 解析参数和配置覆盖。
|
|
243
247
|
示例默认 `selected`,正式 CLI 保留 `strict` 默认;两者均支持显式 `--success-policy`,退出码与报告的 `policy_success` 一致。
|
|
244
248
|
新示例 `summary.json` 使用标准 schema 2 的 `devices`,不再另造 `outcomes`;旧报告可继续用 `review_tftp.rb` 读取。
|
|
245
249
|
TFTP 的 `verification` 汇总与设备条目的 `server_file_verified` 区分上传回执和服务器文件核验,核验成功还包含 `local_file`、`server_archive_file`、`bytes`、`sha256`。
|
|
@@ -268,7 +272,7 @@ HTTP 和 PostgreSQL 默认启用本地清单缓存,有效期三天(259200
|
|
|
268
272
|
|
|
269
273
|
空文件或格式损坏的缓存按未命中处理,重新查询远端;查询失败时,这类文件不能作为回退历史。
|
|
270
274
|
|
|
271
|
-
强刷使用 `net-backup --refresh-inventory`、`fleet.devices(force_refresh: true)`、`fleet.plan_backup(force_refresh: true)`;TFTP 规划也支持此参数。强刷失败同样回退已验证历史。直接注入客户端时不自动缓存,可显式包裹 `Netdisco::
|
|
275
|
+
强刷使用 `net-backup --refresh-inventory`、`fleet.devices(force_refresh: true)`、`fleet.plan_backup(force_refresh: true)`;TFTP 规划也支持此参数。强刷失败同样回退已验证历史。直接注入客户端时不自动缓存,可显式包裹 `Netdisco::Inventory::Cache`。一个包装器的状态描述最近调用,并发共享实例须由调用方同步。有界跨进程锁合并普通过期刷新,独立强刷请求各自访问远端。
|
|
272
276
|
|
|
273
277
|
## 配置批次与接口修正
|
|
274
278
|
|
|
@@ -292,8 +296,8 @@ puts "清单 #{batch.summary[:total]},成功 #{batch.summary[:succeeded]},
|
|
|
292
296
|
|
|
293
297
|
接口应用复用单设备拓扑操作,保留证据重验、配置回读和持久化确认,不将审批计划当作普通脚本执行。脚本与独立计划应用要求 `confirmed: true`;显式同步调用本身表达修改意图,不自动重放命令。每台任务独占并关闭连接器;普通失败隔离为设备结果,中断停止并等待全部工作线程。跨设备已完成的变更不会自动回滚。
|
|
294
298
|
|
|
295
|
-
`
|
|
299
|
+
`Operations::Batch` 独立于备份报告,`outcomes` 保留原 `Result` 或计划、完成步骤和第一故障;`:partial` 表示已有工作后出错,缺少凭据也使批次不成功。`plans` 只选完整成功的规划结果。`to_h` 仅输出安全诊断和数量,不展开命令、回显、凭据或证据。`on_start` 和 `on_result` 在工作线程执行,回调须线程安全;普通回调故障记录后继续,不重复设备操作。日志使用 `ssh.log_directory`。
|
|
296
300
|
|
|
297
301
|
每台设备独占会话,在操作和关闭完成后发布一个不可变终态。连接、凭据、执行和关闭的普通故障只影响该设备,其他运行中或排队任务继续。整批调度结束后返回完整结果;`summary` 和 `to_h[:summary]` 提供 `total`、`succeeded`、`failed`,满足总数 = 成功 + 失败,并细分 `partial`、`missing_credentials` 和 `callback_errors`。总数是本次请求并调度的设备数量;部分完成与缺少凭据计入失败,回调故障单列,不改写设备执行结果。空批次各项为零且状态为 `no_devices`。库不直接输出终端内容,调用方可将 `to_h` 导出 JSON 报告。设备上的已完成变更不能回滚;全批审批预检和显式中断仍维持原有失败边界。
|
|
298
302
|
|
|
299
|
-
其他独立任务可加载 `net/connector/
|
|
303
|
+
其他独立任务可加载 `net/connector/concurrency/pool`,通过 `Net::Connector::Concurrency::Pool.new(concurrency: 4).map(items) { |item| ... }` 执行。结果按输入顺序返回,全部线程建立成功才运行块,未处理异常会停止线程池并回到调用线程。业务代码负责决定哪些普通错误转换为单任务结果。显式参数优先于 `NC_CONCURRENCY` 环境变量,默认 4、上限 50。
|