vxlan 0.2.3 → 0.3.1

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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +69 -0
  3. data/README-zh.md +32 -4
  4. data/README.md +32 -4
  5. data/bin/README.md +203 -0
  6. data/bin/vxlan +8 -0
  7. data/docs/architecture-zh.md +62 -60
  8. data/docs/evidence-contracts.md +54 -0
  9. data/docs/remediation.md +84 -0
  10. data/docs/review-2026-10-19.md +31 -0
  11. data/docs/review-2026-10-21.md +19 -0
  12. data/docs/superpowers/plans/2026-10-19-command-line.md +69 -0
  13. data/docs/superpowers/plans/2026-10-19-connector-integration.md +83 -0
  14. data/docs/superpowers/plans/2026-10-19-evidence-contracts.md +64 -0
  15. data/docs/superpowers/plans/2026-10-19-vxlan-examples.md +47 -0
  16. data/docs/superpowers/plans/2026-10-20-fabric-consistency.md +28 -0
  17. data/docs/superpowers/specs/2026-10-19-command-line-design.md +78 -0
  18. data/docs/superpowers/specs/2026-10-19-connector-integration-design.md +100 -0
  19. data/docs/superpowers/specs/2026-10-19-evidence-contracts.md +11 -0
  20. data/examples/README.md +20 -0
  21. data/examples/collect.rb +8 -0
  22. data/examples/parse.rb +5 -0
  23. data/lib/vxlan/acl_policy.rb +50 -0
  24. data/lib/vxlan/change_plan/svi_acl.rb +76 -0
  25. data/lib/vxlan/change_plan/svi_gateway.rb +36 -0
  26. data/lib/vxlan/change_plan/vlan_vni.rb +40 -0
  27. data/lib/vxlan/change_plan.rb +131 -0
  28. data/lib/vxlan/cisco_nxos/configuration_state.rb +1 -4
  29. data/lib/vxlan/cisco_nxos/evpn_l2route.rb +1 -1
  30. data/lib/vxlan/cisco_nxos/parsers/show_bgp_l2vpn_evpn_summary.rb +65 -11
  31. data/lib/vxlan/cisco_nxos/parsers/show_cdp_neighbors_detail.rb +32 -8
  32. data/lib/vxlan/cisco_nxos/parsers/show_mac_address_table.rb +1 -1
  33. data/lib/vxlan/cisco_nxos/parsers/show_nve_peers.rb +3 -2
  34. data/lib/vxlan/cisco_nxos/parsers/show_nve_vni.rb +9 -1
  35. data/lib/vxlan/cisco_nxos/parsers/show_running_config.rb +11 -5
  36. data/lib/vxlan/cisco_nxos/parsers/show_vpc_brief.rb +10 -4
  37. data/lib/vxlan/cisco_nxos/syntax/policies.rb +16 -0
  38. data/lib/vxlan/cisco_nxos/syntax/routing.rb +16 -6
  39. data/lib/vxlan/cli/apply.rb +172 -0
  40. data/lib/vxlan/cli/collect.rb +210 -0
  41. data/lib/vxlan/cli/connector.rb +23 -0
  42. data/lib/vxlan/cli/options.rb +311 -0
  43. data/lib/vxlan/cli/parse.rb +58 -0
  44. data/lib/vxlan/cli/report.rb +223 -0
  45. data/lib/vxlan/cli/review/fabric.rb +102 -0
  46. data/lib/vxlan/cli/review/report.rb +165 -0
  47. data/lib/vxlan/cli/review.rb +125 -0
  48. data/lib/vxlan/cli/templates/env.example +12 -0
  49. data/lib/vxlan/cli/templates/vxlan.yml +32 -0
  50. data/lib/vxlan/cli.rb +41 -0
  51. data/lib/vxlan/collector.rb +59 -28
  52. data/lib/vxlan/config/evidence.rb +18 -0
  53. data/lib/vxlan/config/review.rb +56 -0
  54. data/lib/vxlan/{configuration.rb → config.rb} +1 -1
  55. data/lib/vxlan/fabric/review.rb +327 -0
  56. data/lib/vxlan/fabric/scope.rb +43 -0
  57. data/lib/vxlan/observation.rb +3 -0
  58. data/lib/vxlan/recommendations.rb +193 -0
  59. data/lib/vxlan/service/catalog.rb +77 -0
  60. data/lib/vxlan/service/mapping.rb +53 -0
  61. data/lib/vxlan/snapshot.rb +3 -0
  62. data/lib/vxlan/subnet_index.rb +88 -0
  63. data/lib/vxlan/version.rb +1 -1
  64. data/lib/vxlan.rb +4 -2
  65. metadata +138 -7
  66. data/lib/vxlan/cisco_nxos/configuration.rb +0 -10
  67. data/lib/vxlan/configuration_review.rb +0 -54
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 715f96e8f586f8a7bacd62d8a7d5e47d4665884cdc20c3953d75c6282184955d
4
- data.tar.gz: c3e70fb64cb7677d3e960d05f11622720f0a5842fc0171c7775047d0fd6b8d8a
3
+ metadata.gz: 2efb2207fd79cd9e4ef9724ebca3a5da93aa10db56719c1a0b6f4ac3562ba444
4
+ data.tar.gz: 73730c534034650b6bf44e917675dab25e445f5dcb1967263f3610a2324f3830
5
5
  SHA512:
6
- metadata.gz: c13eb74ea3ec0e75a8985a3bdf92503db849a6fc55e90af1a7a8ce051eaa810cdf50b25ab90869dae9696ca85bec142a83f0b7bbd649c5e6a7c6aea4019a09b6
7
- data.tar.gz: 2bbb1204ab00cfcc50998a878b3d61c8614b03cc158833fecb1c3f1a2835672751bdd89d36e9dd79eca3cd893f91dfb4870c5ff8499817a2fe53bc758ec5eee4
6
+ metadata.gz: 869198020e0207f4896732548a88cf2c3b0abef61dd143c025636021b49b513b54848645a10b26a18624961386eaf524cd9f2588da7d7b7843812e549d8ad0ff
7
+ data.tar.gz: fcf9a413bd76e02fcae70f8af7f52e5de9ebd5ddf836bd86d3e45c4f404368bb3bdcdb1a5491346b1220ddc8f2a5d250fd418ec6bbcde8255c6a4576ff4b2a57
data/CHANGELOG.md CHANGED
@@ -2,6 +2,75 @@
2
2
 
3
3
  Changes to the public contract are recorded here. Versions follow Semantic Versioning.
4
4
 
5
+ ## Unreleased
6
+
7
+ ## 0.3.1 (2026-10-21)
8
+
9
+ - Index Fabric address-group evidence by referenced object, preserving host order and missing dependencies without repeatedly searching every host's reference list.
10
+ - Add repository-specific AGENTS.md and a full Fabric review benchmark.
11
+
12
+ ## 0.3.0 (2026-10-20)
13
+
14
+ - Require ctx_driver 0.2.4+ for the current net-connector session protocol; CLI configuration and progress use net-connector 0.16.0.
15
+
16
+ - 设备目录只保留 TXT 诊断,结构化采集事实统一移入 evidence/;离线审查只读取新目录。
17
+ - Review 布局 v3:对齐 topology 的 summary.txt/json、devices/*.txt、scripts/*.cfg、plan.json/SHA256 和 events.jsonl;不生成 Markdown。诊断先合并后发布,聚合计划必须 --item 选择单项并交互确认。
18
+
19
+ - Rename the public configuration parser to `Vxlan::Config` (`vxlan/config`), updating CLI callers, examples, tests and documentation without compatibility aliases. Evidence and review helpers now live under `Config::Evidence` and `Config::Review`.
20
+
21
+ - 与 net-connector 备份共用批次终端进度、阶段心跳、异常分类和结束摘要;JSON 独立输出,终端故障保留安全诊断且不重采。初始化并发继承公共 `NC_PARALLEL`,不再把公共值或默认 4 固化进 YAML。
22
+
23
+ - Model ACL meaning as an immutable `AclPolicy` and each supported change as a validated `ChangePlan` subtype. Use one frozen plan through confirmation, sending and readback; copy session snapshots so a reused reader buffer cannot overwrite the starting state. Reuse resolved ACL policies within one review without caching across calls.
24
+ - Share the complete-configuration gate across local advice, Fabric review and typed plans; reject ambiguous offline device identities, and report L2 VLAN differences, single-leaf VNI reuse, unequal-prefix subnet overlaps and unknown ACL dependencies.
25
+ - Recheck gateway addresses and overlapping subnets, VNI uniqueness and newly created ACL binding scope after apply; require an eligible before snapshot in `ChangePlan#satisfied?` and preserve uncertain outcomes when target fields appear alongside unplanned configuration drift.
26
+ - Reject repeated collection callbacks without replaying reads or overwriting acquired facts; validate BGP identities across repeated logical scopes and ASPLAIN/ASDOT forms.
27
+ - Validate BGP scope and contradictory routing identities, exclude ambiguous CDP fields and reject invalid NVE multicast values.
28
+ - Persist new report directory entries before execution, share device artifact naming, index address-group sequences and reuse one configuration fingerprint per device.
29
+ - Remove the legacy `CiscoNxos::Configuration` loading alias and `finish` alias; use `ConfigurationState#finalize_facts` directly with `Vxlan::Config` as the public parser.
30
+
31
+ - CLI 配置统一使用 net-connector 0.16.0 的分层加载器,遵循命令行 > 进程环境 > YAML > `.env` > 默认值;支持公共配置复用、来源追踪及用户目录初始化。
32
+
33
+ - Isolate each collection's effective environment and freeze its validated Fabric policy before opening sessions; switching environment files no longer reuses previous credentials or inventory defaults.
34
+ - Require aggregate plan checksums and explicit item selection for every apply; reject standalone legacy plans and missing/repeated session callbacks, and preserve uncertain finalization outcomes.
35
+ - Model Fabric roles and deployed services explicitly, including incomplete VLAN/NVE/EVPN associations; check inherited multicast, tenant routing, ACL dependencies and cross-VNI subnet conflicts before proposing a typed VLAN/VNI association.
36
+
37
+ - Audit explicitly scoped Fabric leaf groups for common deployed VNI gateway and ordered ACL consistency; preserve deployment differences, flag undefined attached ACLs and cross-VNI subnet conflicts, and block conflicting policy propagation.
38
+
39
+ - Make configuration script export opt-in with `--scripts`; add typed per-device plans and a TTY-only `apply` command with exact confirmation, fresh configuration guards, durable step checkpoints, no retry/automatic rollback, and configuration readback verification.
40
+
41
+ - Generate evidence-backed, review-only remediation recommendations during collection and through the offline `review --batch` command, including prerequisites, blocked parameters, conditional rollback, verification commands and source hashes. Configuration drafts are fully commented; no device changes are executed.
42
+
43
+ - Support live NX-OS variants: unavailable NVE router MACs, empty optional CDP UUIDs, starred down vPC members and wrapped consistency reasons, plus MAC/L2RIB flag legends.
44
+ - Derive BGP route-type columns from supported header declarations, with or without a repeated `PfxRcd` column; retain identity, duplicate-column and prefix-count validation.
45
+ - Exclude local Netdisco inventory caches from version control.
46
+
47
+ - Validate BGP route-type totals and isolate equivalent configured IPv6 host/prefix identities without changing retained key spelling.
48
+ - Publish incomplete summary checkpoints before finalization; retain safe checkpoints, recover committed failures/cancellation, invalidate stale success on repeated finish, and report unconfirmed recovery without replaying device queries.
49
+ - Add traceable evidence specimens, independent literal expectations, private saved-capture replay and isolated targeted mutation verification tools.
50
+
51
+ - Centralize static and discovered device validation before public configuration output, reject false filter lists, and isolate state when a CLI runner is reused.
52
+ - Index completed hosts once when building pending-target summaries and document safe report publication states.
53
+ - Normalize BGP summary peer addresses before identity checks and prefix-statistics association.
54
+ - Validate configured neighbor addresses without discarding valid siblings, and keep misplaced BGP address-family switches partial using one shared routing-scope guard.
55
+
56
+ - Align CLI help, plan/no-progress aliases, initialization guidance and operator documentation with net-connector examples; preserve invocation-directory defaults.
57
+
58
+ - Add the installable `vxlan collect` / `vxlan parse` command, sharing implementation with thin source examples.
59
+ - Move CLI implementation and templates out of examples; preserve source defaults and use user working directories for installed commands.
60
+ - Remove superseded examples/support files and duplicate example templates.
61
+
62
+ - Load existing environment defaults before initializing host configuration, honoring the selected config path without copying credentials.
63
+ - Preserve batch summaries and pending targets on scheduler failures; retain an incomplete execution status even after all device reports were saved, without exposing exception details.
64
+ - Mark every requested dimension failed when a connector returns without providing a session, instead of reporting empty evidence as complete.
65
+
66
+ - Collect native NX-OS observations under one operation lease without redundant session wrapping; preserve acquired facts on finalization failure.
67
+ - Reject prematurely exited/killed collection workers and join all owned threads before propagating failure.
68
+ - Register acquired results before publication, distinguish saved reports from acquired evidence, and preserve cancellation when summary publication also fails.
69
+ - Reject non-private or symlink report roots; sync published directory entries and report safe publication phases without exposing raw filesystem errors.
70
+
71
+ - Add borrowed-session collection with configuration-first dependent observations; retain requested dimension order.
72
+ - Add host examples for configurable batch collection, safe per-device reports and offline file parsing. Keep net-connector and dotenv outside core runtime dependencies.
73
+
5
74
  ## 0.2.3 (2026-10-18)
6
75
 
7
76
  - Validate optional IPv4 next hops following static-route output interfaces without changing route fields or option text.
data/README-zh.md CHANGED
@@ -52,13 +52,29 @@ observation.records.each { |record| p record }
52
52
  # 单个已解析邻居仅是一项观测,不能证明整个 Fabric 健康。
53
53
  ```
54
54
 
55
+ ## 正式命令行入口
56
+
57
+ 安装包提供 `vxlan collect` 和 `vxlan parse`,正式实现在 `lib/vxlan/cli/`;`examples/` 保留薄入口与离线演示,两种入口共用实现。
58
+
59
+ ```sh
60
+ gem install vxlan
61
+ # 联网采集与读取 .env 所需的可选依赖:
62
+ gem install net-connector -v '~> 0.16.0'
63
+ vxlan --help
64
+ vxlan collect --init --non-interactive
65
+ vxlan collect --inventory-only
66
+ vxlan parse --file running.cfg --complete
67
+ ```
68
+
69
+ 统一按 `/etc/net-connector` → `/usr/local/etc/net-connector` → `$XDG_CONFIG_HOME/net-connector`(默认 `~/.config/net-connector`)→ 脚本目录 → 启动目录 → 显式文件逐层覆盖。每层可放共享 `net-connector.yml`、专用 `vxlan.yml` 和 `.env`。参数优先级为 **命令行 > 进程环境 > YAML > .env > 默认值**,设备数组整体替换。文件内相对路径按来源目录解析。`--init` 在用户配置目录创建缺失模板,`--show-config` 附带来源路径;报告默认仍写启动目录 `vxlans/`。离线解析与帮助不加载连接器。详见[使用说明](bin/README.md)。
70
+
55
71
  ## 公开契约与限制
56
72
 
57
- `Configuration.new.parse(text, complete: false)` 返回配置观察。`RuntimeParser.new(platform: :cisco_nxos, model: nil).parse(name, text, complete: false)` 返回具名运行观察。`ParserRegistry.fetch(platform, model:)` 提供按命令解析的声明式策略。
73
+ `Config.new.parse(text, complete: false)` 返回配置观察。`RuntimeParser.new(platform: :cisco_nxos, model: nil).parse(name, text, complete: false)` 返回具名运行观察。`ParserRegistry.fetch(platform, model:)` 提供按命令解析的声明式策略。
58
74
 
59
75
  传输完整是解析完整的必要条件,不是充分条件。未知语法、身份冲突、不完整引用和无法证明为空的表格保留诊断。配置关联核查与语法完整性、运行健康分别表达。IPv6 prefix-list 事实不代表 IPv6 underlay 库存能力。
60
76
 
61
- `Collector#collect(connector:, target:, fabric_key:, model: nil, dimensions:)` 使用宿主提供的 connector;设备身份、凭据、持久化、库存对账和并发策略由宿主负责。本 gem 不包含 fabric 规划、配置下发、Rails 模型或 `Vxlan::Sync`。加载库或运行离线示例不会访问设备。
77
+ `Collector#collect(connector:, target:, fabric_key:, model: nil, dimensions:)` 使用宿主提供的 connector;设备身份、凭据、持久化、库存对账和并发策略由宿主负责。CLI 提供显式范围的 Fabric 审查、可选变更建议及受支持增量的交互下发;核心库独立于 Rails 和数据库。加载库或运行离线示例不会访问设备。
62
78
 
63
79
  采集器在打开连接前复制目标身份、Fabric 身份和维度选择。`Observation` 的名称必须为 Symbol;`Snapshot` 的维度值必须是名称与键一致的 `Observation`。两种对象的字符串插值均使用只含元数据的 `inspect` 表示。
64
80
 
@@ -66,10 +82,16 @@ observation.records.each { |record| p record }
66
82
 
67
83
  详细厂商语义、历史验证记录和 Motor 专用集成说明保留在[架构参考](docs/architecture-zh.md)。其中宿主集成代码需要 Motor,不属于独立 gem API。适配层位于 [Motor 仓库](https://github.com/gatework/motor/tree/main/backend/lib) 的 `backend/lib/baseline`、`backend/lib/vxlan` 和 `backend/lib/wireless`。
68
84
 
69
- 生命周期 connector 是宿主适配器,提供 `open { |session| }`,VXLAN 和 Wireless 还要求 `platform`;原生 `Net::Connector::Base` 实例并不提供这一宿主生命周期协议。已连接的原生会话可传入 `CtxDriver::Reader` 或 `CtxChecker::Collector#collect_session`,不会隐式连接或重试。
85
+ 生命周期 connector 是宿主适配器,提供 `open { |session| }`,VXLAN 和 Wireless 还要求 `platform`;原生 `Net::Connector::Base` 实例并不提供这一宿主生命周期协议。已连接的原生会话可传入 `CtxDriver::Reader` 或 `Vxlan::Collector#collect_session`,不会隐式连接或重试。
86
+
87
+ 原生会话由宿主用 `native.with_operation(:vxlan)` 包围整次采集,防止其他任务插入命令。需要在收尾失败后保留事实时,在操作块内登记 snapshot,分别处理关闭或租约退出故障。批量 CLI 拥有此生命周期,报告分别记录已采集证据与文件保存状态;私有目录及取消行为见[CLI 使用说明](bin/README.md)。
88
+
89
+ `Collector#collect_session(session:, target:, fabric_key:, platform: :cisco_nxos, model: nil, dimensions:)` 可借用已打开的驱动会话,不负责连接、关闭、提权或重连。选中配置时先采集配置,再处理依赖配置的运行维度;结果顺序仍与请求相同。
70
90
 
71
91
  ## 领域术语
72
92
 
93
+ NVE 的 `n/a` Router MAC 保留为 `nil`,CDP 的空 `DC_UUID` 也保留未知值。vPC 的 `down*` 解析为 `state: "down"`,同时保留 `forwarding_via_peer_link: true`;仅拼接已识别的同一成员续行。BGP 按表头声明解析已支持的路由类型列,兼容省略重复 `PfxRcd` 的格式,类型统计仍不得超过主表前缀总数。空命令正文、没有明确空表或总数证据的 L2RIB 结果仍为部分证据。
94
+
73
95
  VLAN ID、VNI、VRF、NVE 成员是不同身份。配置审查通过 VNI 关联 VLAN 映射与 NVE 成员,不推断运行可达性。`BgpNeighbors` 枚举应用 peer-template 继承后的配置邻居,不代表已建立的 BGP 会话。`PrefixListReferences` 表达 route-map 选择器及路由使用方的引用关系,引用本身不能证明路由被接受。
74
96
 
75
97
  关联诊断包括:显式 EVPN 或 VRF 定义与 NVE 成员二层/三层角色矛盾时的 `vni_layer_conflict`,以及三层 NVE 成员没有对应 VNI 的配置 VRF 时的 `nve_l3_without_vrf`。VLAN 映射本身不能证明二层角色,支持通过 VLAN 承载的三层 VNI。这些诊断仅基于完整配置证据生成,不改变语法解析状态。
@@ -82,7 +104,7 @@ prefix-list 或 route-map 在同种类、同名称内出现重复序号时,排
82
104
 
83
105
  共享类按实际职责命名,平台信息放在命名空间中。直接对应设备命令的解析器保留文件名和类名。
84
106
 
85
- `CiscoNxos::ConfigurationState` 持有单次解析期间的可变事实,`Vxlan::Configuration` 是公开解析入口。原 `CiscoNxos::Configuration` 常量及其 `finish` 方法保留为兼容别名。内部方法名区分文本解析(`parse_next_hops`)、诊断记录(`unparsed_records`)和冲突排除(`exclude_ambiguous_records!`,移除重复身份的全部记录)。
107
+ `CiscoNxos::ConfigurationState` 持有单次解析期间的可变事实,通过 `finalize_facts` 归约;`Vxlan::Config` 是公开解析入口。内部方法名区分文本解析(`parse_next_hops`)、诊断记录(`unparsed_records`)和冲突排除(`exclude_ambiguous_records!`,移除重复身份的全部记录)。
86
108
 
87
109
  ```sh
88
110
  bundle install
@@ -108,3 +130,9 @@ CI 在 Linux、macOS 上执行测试、lint、示例、构建和隔离安装。`
108
130
  ## 许可证
109
131
 
110
132
  MIT,见 [LICENSE](LICENSE)。
133
+
134
+ ## 修复建议
135
+
136
+ `vxlan collect` 默认输出逐设备诊断,使用 `--scripts` 可选导出配置建议;`vxlan review --batch DIR` 可离线补生成既有报告的候选配置、条件回退和只读验收命令。导出不会执行变更;独立 `apply --plan FILE --item ID` 必须在真实终端明确确认,配置漂移或失败即停止。详见[修复建议说明](docs/remediation.md)。 业务分层、会话所有权与执行边界见[架构说明](docs/architecture-zh.md)。
137
+
138
+ 报告阅读顺序与 net-connector topology 一致:`summary.txt` → `devices/*.txt` → `scripts/*.cfg`。不生成 Markdown 报告。所有可执行增量汇总于带 SHA256 校验的 `plan.json`,通过 `vxlan apply --plan plan.json --item ID` 选择一项并交互确认。
data/README.md CHANGED
@@ -52,13 +52,31 @@ observation.records.each { |record| p record }
52
52
  # 单个已解析邻居仅是一项观测,不能证明整个 Fabric 健康。
53
53
  ```
54
54
 
55
+ ## Command line
56
+
57
+ The gem installs `vxlan`; its implementation lives in `lib/vxlan/cli/`. The scripts in `examples/` are thin callers of the same implementation, plus a self-contained offline demonstration.
58
+
59
+ ```sh
60
+ gem install vxlan
61
+ # Optional dependencies for live collection and .env files:
62
+ gem install net-connector -v '~> 0.16.0'
63
+ vxlan --help
64
+ vxlan collect --init --non-interactive
65
+ vxlan collect --inventory-only
66
+ vxlan parse --file running.cfg --complete
67
+ ```
68
+
69
+ Configuration is layered from `/etc/net-connector`, `/usr/local/etc/net-connector`, `$XDG_CONFIG_HOME/net-connector` (default `~/.config/net-connector`), the entry script directory, the invocation directory, and an explicit file. Each directory may contain shared `net-connector.yml`, native `vxlan.yml`, and `.env`. Values follow **CLI > process environment > YAML > .env > defaults**; device arrays replace rather than append. Relative file paths resolve beside their source file. `--init` creates missing files in the user configuration directory; `--show-config` includes source paths without credential values. Reports default to the invocation directory's `vxlans/`. Offline parsing and help do not load the connector. See [the CLI guide](bin/README.md).
70
+
55
71
  ## Public contract and limits
56
72
 
57
- `Configuration.new.parse(text, complete: false)` returns a configuration observation. `RuntimeParser.new(platform: :cisco_nxos, model: nil).parse(name, text, complete: false)` returns a named runtime observation. `ParserRegistry.fetch(platform, model:)` exposes a declared profile for command-specific parsing.
73
+ `Config.new.parse(text, complete: false)` returns a configuration observation. `RuntimeParser.new(platform: :cisco_nxos, model: nil).parse(name, text, complete: false)` returns a named runtime observation. `ParserRegistry.fetch(platform, model:)` exposes a declared profile for command-specific parsing.
58
74
 
59
75
  Complete transport is necessary but insufficient for complete parsing: unknown syntax, conflicting identities, incomplete references, and ambiguous empty tables retain diagnostics. Configuration association findings are separate from syntax completeness and runtime health. IPv6 prefix-list facts do not imply IPv6 underlay inventory support.
60
76
 
61
- `Collector#collect(connector:, target:, fabric_key:, model: nil, dimensions:)` uses a host-supplied connector; device identity, credentials, persistence, reconciliation, and concurrency policy belong to the host. This gem includes no fabric planner, provisioning engine, Rails models, or `Vxlan::Sync`. Loading or running the offline example does not access a device.
77
+ `Collector#collect(connector:, target:, fabric_key:, model: nil, dimensions:)` uses a host-supplied connector; device identity, credentials, persistence, reconciliation, and concurrency policy belong to the host. The CLI adds scoped Fabric review, opt-in change suggestions and interactive application of supported changes. The core remains independent of Rails and databases. Loading or running the offline example does not access a device.
78
+
79
+ `Collector#collect_session(session:, target:, fabric_key:, platform: :cisco_nxos, model: nil, dimensions:)` borrows an already opened driver session (including the optional native adapter) without opening, closing, escalating privilege or retrying it. When configuration is selected, it is read before dimensions that depend on it; result order still matches the requested dimensions.
62
80
 
63
81
  The collector copies target identity, fabric identity, and dimension selection before opening the connection. `Observation` names must be symbols; each `Snapshot` dimension must hold an `Observation` with a matching name. Both objects use their metadata-only `inspect` representation for string interpolation.
64
82
 
@@ -66,10 +84,14 @@ Conflicting singleton configuration values are excluded and reported as partial
66
84
 
67
85
  Detailed vendor behavior, historical validation notes, and Motor-only integration are preserved in [the architecture reference](docs/architecture-zh.md). Host integration examples in that reference require Motor; they are not standalone gem APIs. Motor adapters live under `backend/lib/baseline`, `backend/lib/vxlan`, and `backend/lib/wireless` in the [Motor repository](https://github.com/gatework/motor/tree/main/backend/lib).
68
86
 
69
- The lifecycle connector is a host adapter exposing `open { |session| }` (and `platform` for VXLAN and Wireless). It is distinct from a native `Net::Connector::Base` device instance. Borrowed native sessions are accepted by `CtxDriver::Reader` and `CtxChecker::Collector#collect_session`; they are never implicitly connected or retried.
87
+ The lifecycle connector is a host adapter exposing `open { |session| }` (and `platform` for VXLAN and Wireless). It is distinct from a native `Net::Connector::Base` device instance. Borrowed native sessions are accepted by `CtxDriver::Reader` and `Vxlan::Collector#collect_session`; they are never implicitly connected or retried.
88
+
89
+ For native sessions, the host holds `native.with_operation(:vxlan)` around the full collection so other tasks cannot interleave commands. Register the snapshot inside that block if it must survive a later lease/close failure; the host reports finalization errors separately. The collection CLI owns this lifecycle; its reports distinguish acquired evidence from confirmed file publication. See [the CLI guide](bin/README.md) for private output directories and cancellation behavior.
70
90
 
71
91
  ## Domain vocabulary
72
92
 
93
+ Runtime variants preserve unavailable NVE router MACs as `nil`, optional empty CDP `dc_uuid` as `nil`, and starred vPC `down*` members as `state: "down"` with `forwarding_via_peer_link: true`. Wrapped vPC consistency/reason fields are joined only for the recognized continuation. BGP prefix statistics follow supported route-type columns in the header, with or without `PfxRcd`, and remain bounded by the main neighbor's received-prefix count. A blank command body or an empty L2RIB table without explicit empty/count evidence remains partial.
94
+
73
95
  VLAN IDs, VNIs, VRFs, and NVE members are separate identities. Configuration review joins VLAN mappings and NVE members by VNI; it does not infer operational reachability. `BgpNeighbors` enumerates configured neighbors after peer-template inheritance, not established BGP sessions. `PrefixListReferences` describes route-map selectors and their routing consumers; those references do not by themselves prove route acceptance.
74
96
 
75
97
  Association findings include `vni_layer_conflict` for explicit EVPN or VRF definitions that disagree with the NVE member's L2/L3 role, and `nve_l3_without_vrf` for an L3 NVE member without a configured VRF using its VNI. A VLAN mapping alone does not establish an L2 role: VLAN-backed L3 VNIs are supported. These findings are emitted only from complete configuration evidence and do not change the syntax status.
@@ -82,7 +104,7 @@ Repeated prefix-list or route-map sequence identities are excluded within their
82
104
 
83
105
  Name shared classes by their responsibility and use the namespace for platform context. Preserve filenames and class names that directly match device commands.
84
106
 
85
- `CiscoNxos::ConfigurationState` holds mutable facts during a single parse; `Vxlan::Configuration` is the public parsing entry point. The former `CiscoNxos::Configuration` constant and its `finish` method remain compatible aliases. Internal method names distinguish parsing (`parse_next_hops`), diagnostics (`unparsed_records`), and conflict exclusion (`exclude_ambiguous_records!`, which removes every record with a repeated identity).
107
+ `CiscoNxos::ConfigurationState` holds mutable facts during a single parse and reduces them through `finalize_facts`; `Vxlan::Config` is the public parsing entry point. Internal method names distinguish parsing (`parse_next_hops`), diagnostics (`unparsed_records`), and conflict exclusion (`exclude_ambiguous_records!`, which removes every record with a repeated identity).
86
108
 
87
109
  ```sh
88
110
  bundle install
@@ -108,3 +130,9 @@ Publish dependency gems first. A Git tag, a successful build, or a workflow file
108
130
  ## License
109
131
 
110
132
  MIT. See [LICENSE](LICENSE).
133
+
134
+ ## Remediation recommendations
135
+
136
+ `vxlan collect` 默认输出逐设备诊断,使用 `--scripts` 可选导出配置建议;`vxlan review --batch DIR` 可离线补生成既有报告的候选配置、条件回退和只读验收命令。导出不会执行变更;独立 `apply --plan FILE --item ID` 必须在真实终端明确确认,配置漂移或失败即停止。详见[修复建议说明](docs/remediation.md)。 业务分层、会话所有权与执行边界见[架构说明](docs/architecture-zh.md)。
137
+
138
+ Review output follows the net-connector topology layout: `summary.txt`, `summary.json`, `devices/*.txt`, optional `scripts/*.cfg`, and a checksummed `plan.json`. Generated reports contain no Markdown. Select exactly one change with `vxlan apply --plan plan.json --item ID`; interactive confirmation remains mandatory.
data/bin/README.md ADDED
@@ -0,0 +1,203 @@
1
+ # VXLAN 命令行使用说明
2
+
3
+ 脚本的配置、帮助、进度和报告方式参考 net-connector/examples。**Vxlan 核心不依赖 net-connector**;正式实现位于 `lib/vxlan/cli/`,负责清单、凭据、连接、并行和报告;`bin/vxlan` 只加载并调用同一入口。支持 Cisco NX-OS,使用模块声明的固定查询,不执行配置下发。
4
+
5
+ ## 安装与入口
6
+
7
+ Ruby 4.0.6 或更新版本。在源码目录执行 `bundle install` 会从 RubyGems 安装 `ctx_parser`、`ctx_driver` 及开发/示例依赖,不加载相邻工作树。
8
+
9
+ ```sh
10
+ bundle install
11
+ ruby bin/vxlan collect --help
12
+ ruby bin/vxlan parse --examples
13
+ bundle exec ruby examples/offline.rb
14
+ ```
15
+
16
+ 也可以在 `bin/` 中执行 `ruby vxlan collect --help`,或从任意目录指定入口绝对路径。源码入口加载相邻 `lib/`,依赖使用当前 RubyGems/Bundler 环境;不切换 Gemfile、不搜索相邻仓库。安装后使用 `vxlan collect` 和 `vxlan parse`。
17
+
18
+ `bin/` 的公开内容是 `vxlan` 与本说明;现场 `vxlan.yml`、`.env`、`vxlans/` 由用户按需创建,不进入版本库或安装包。配置和凭据模板统一位于 `lib/vxlan/cli/templates/`,使用 `--init` 生成,不维护重复模板。
19
+
20
+ 离线解析和帮助不加载 net-connector。采集配置与联网入口可选依赖 `net-connector ~> 0.16.0`(已包含 `.env` 加载依赖 dotenv)。本仓库 Gemfile 的 `examples` 组已声明连接器,不进入 vxlan.gemspec 的运行依赖。只安装 vxlan gem 的宿主需要自行声明相应可选依赖。
21
+
22
+ ## 正式命令
23
+
24
+ 安装后使用统一入口(联网及读取环境文件仍需可选依赖):
25
+
26
+ ```sh
27
+ gem install vxlan
28
+ gem install net-connector -v '~> 0.16.0'
29
+ vxlan --help
30
+ vxlan collect --init --non-interactive
31
+ vxlan collect --inventory-only
32
+ vxlan parse --file running.cfg --complete
33
+ ```
34
+
35
+ 配置目录从低到高依次为:`/etc/net-connector` → `/usr/local/etc/net-connector` → `$XDG_CONFIG_HOME/net-connector`(默认 `~/.config/net-connector`)→ 当前入口脚本目录 → 启动目录;重复目录只读一次,不向父目录搜索。每个目录先加载共享 `net-connector.yml`,再加载专用 `vxlan.yml`;`--config` 或 `VXLAN_CONFIG` 指定的文件最后覆盖。每层 `.env` 同样叠加,`--env-file` 最后加载;显式文件不存在即报错,自动候选不存在则跳过。
36
+
37
+ 共享文件使用 `common`、`vxlan`、`wireless`、`backup`、`topology` 分区;`common` 只承载 `netdisco`、`inventory`、`ssh`。例如三项目可共用一个文件:
38
+
39
+ ```yaml
40
+ common:
41
+ ssh:
42
+ host_key_policy: strict
43
+ known_hosts: keys/known_hosts
44
+ netdisco:
45
+ url: https://netdisco.example.test
46
+ vxlan:
47
+ parallel: 4
48
+ wireless:
49
+ parallel: 4
50
+ ```
51
+
52
+ 单个 YAML 文件禁止重复键和多个文档,避免设备范围被静默覆盖或忽略。映射递归覆盖,数组整体替换,`false`、空数组和显式 `null` 保留给领域校验。专用配置的非空 `devices` 不会被公共 Netdisco 配置切换成动态清单;专用配置同时声明冲突来源会被拒绝。YAML 和 `.env` 中声明路径相对各自来源文件,CLI 与进程环境路径相对启动目录。报告默认写启动目录 `vxlans/`。
53
+
54
+ 常用选项使用 `-h / --help`;`--help-all` 补充全部参数和环境约定;`--examples` 显示带用途说明的命令范例。这些操作不读取配置、清单或凭据,不创建文件。
55
+
56
+ ## 离线解析
57
+
58
+ ```sh
59
+ ruby bin/vxlan parse --file running.cfg --complete
60
+ ruby bin/vxlan parse --dimension nve_peers --file nve.txt --complete --json
61
+ cat bgp.txt | ruby bin/vxlan parse --dimension bgp_neighbors --complete
62
+ ```
63
+
64
+ `--complete` 是调用方声明“输入已完整采集”,默认未声明,因而保留不完整证据。完整传输中仍有未知语法或冲突时,结果仍可能是 `partial`。默认只打印状态、记录数、诊断代码;`--json` 显式导出解析事实,可能包含运行配置中的敏感字段,请由宿主管理其输出权限。支持维度由 `--help` 列出;configuration 使用配置解析器,其余使用 RuntimeParser。
65
+
66
+ ## 初始化、配置与环境
67
+
68
+ ```sh
69
+ ruby bin/vxlan collect --init --non-interactive
70
+ ```
71
+
72
+ 创建用户配置目录中缺失的 `vxlan.yml` 和 `.env`(或显式 `--config` / `--env-file` 路径),保留已有文件。每个文件先写临时文件,再排他发布,权限为 0600;创建文件后提示检查配置及凭据,再立即退出,不读取清单、不连接设备。缺失配置时,交互终端提供创建选项;自动化不询问、不读取 stdin、不自动创建文件,直接提示 `--init`。`--interactive` 要求真实终端,`--non-interactive` 禁用问答;不会在自动化中消费 stdin。
73
+
74
+ 初始化同样先读取已有 `.env`:其中的 `VXLAN_CONFIG` 选择待创建路径,公开参数作为模板默认值;进程环境优先于 `.env`,CLI 覆盖公开参数,凭据不会复制进 YAML。
75
+
76
+ 模板默认无设备:填写明确目标后才能采集,不自动扫描文档地址或展开网段。
77
+
78
+ ```yaml
79
+ fabric: LAB
80
+ parallel: 4
81
+ directory: vxlans
82
+ dimensions: [configuration, nve_peers, nve_vnis, bgp_neighbors, vpc, port_channels]
83
+ ssh:
84
+ host_key_policy: strict
85
+ command_timeout: 60
86
+ login_timeout: 15
87
+ devices:
88
+ - host: 192.0.2.10
89
+ name: LEAF-01
90
+ model: N9K-C93180YC-FX
91
+ - host: 192.0.2.11
92
+ name: LEAF-02
93
+ ```
94
+
95
+ 将文档地址替换为真实目标。`devices` 仅接受 `host`、`name`、`model`;地址须为 IP,同一规范化地址不得重复。YAML 不接受密码、任意命令或未声明字段。默认采集全部 12 个维度,大型 MAC/L2RIB 表可通过 dimensions 按需选择。选择了 configuration 时,无论它在列表中何处,均先采集配置来判断未启用功能;最终维度结果保持请求顺序。
96
+
97
+ `.env` 示意:
98
+
99
+ ```dotenv
100
+ NC_DEVICE_USERNAME=operator
101
+ NC_DEVICE_PASSWORD='replace-me'
102
+ # 可选,已具备查询权限时无需启用密码:
103
+ # NC_ENABLE_PASSWORD='replace-me'
104
+ ```
105
+
106
+ 用户名必须明确;没有密码时允许 SSH key/agent,脚本不会在终端交互索取密码。按平台覆盖使用 `NC_CISCO_NXOS_USERNAME`、`NC_CISCO_NXOS_PASSWORD`。密码包含 `#`、`$` 时请使用单引号。已有进程环境优先于 `.env`。
107
+
108
+ 公开参数优先级是 **CLI > 原始进程环境 > YAML > .env > 内置默认值**。环境默认包括 `VXLAN_FABRIC`、`VXLAN_PARALLEL`(缺失时使用 `NC_PARALLEL`)、`VXLAN_DIRECTORY`;`VXLAN_CONFIG` 指定默认配置路径,`--config` 可以覆盖,空白的 `VXLAN_CONFIG` 不指定额外文件;`--env-file` 指定其他环境文件。CLI/进程环境中的显式配置文件路径相对启动目录解析,YAML 中的输出目录、known_hosts 和 netdisco_config 路径相对配置文件所在目录解析,不通过 `chdir` 改变宿主目录。
109
+
110
+ SSH 默认严格校验主机密钥。为实际设备准备 known_hosts,或在已接受首次信任风险时显式设置 `host_key_policy: accept_new`;始终拒绝已变更密钥。端口可用 `ssh.port` 设置。并发继承公共 `NC_PARALLEL`,未配置时为 4,允许 1~500,单台设备始终顺序查询。宿主调度独立于连接器内部类,创建线程的闸门和异常回收保证失败或中断后不遗留工作线程;文件描述符不足时在设备连接前提高本进程软限制或明确拒绝过高并发。配置预检不等于设备认证成功。
111
+
112
+ ## 筛选、预览与执行
113
+
114
+ ```sh
115
+ ruby bin/vxlan collect --inventory-only --json
116
+ ruby bin/vxlan collect --show-config
117
+ ruby bin/vxlan collect --hosts 192.0.2.0/24 --name leaf --exclude-name spare --inventory-only
118
+ ruby bin/vxlan collect --host 192.0.2.10 --dimensions configuration,nve_peers -p 4
119
+ ruby bin/vxlan collect --name leaf --verbose
120
+ ruby bin/vxlan collect --json --quiet
121
+ ```
122
+
123
+ 地址筛选只匹配清单已有设备,支持 IP/CIDR;不支持扫描或范围展开。同类 CLI 条件取并集并覆盖对应 YAML 条件;地址和名称取交集,排除优先,名称为忽略大小写的子串。`--host` 同样是清单筛选,不能代替 devices 清单。`--plan` 与 `--inventory-only` 等价,不读取设备凭据或创建报告目录;`--show-config` 输出公开配置以及 `sources` 中的配置文件、环境文件和 YAML 字段来源,不展开环境密码。所有采集配置入口使用共享 net-connector 加载器;静态预览不建立网络连接。
124
+
125
+ 可选复用 net-connector 的 Netdisco YAML:
126
+
127
+ ```yaml
128
+ netdisco_config: /path/to/net-connector/examples/backup.yml
129
+ devices: []
130
+ ```
131
+
132
+ 这只复用设备发现和已配置的筛选策略,选择 ready 的 `cisco_nxos` 设备;只校验并传递外部文件的 `netdisco` / `inventory` 分区,以及对应公共环境字段。清单字段或未知顶层名称有误仍会停止;其他已知分区的备份、拓扑、SSH、TFTP 策略不参与清单预检。Netdisco 的 HTTP/PostgreSQL/缓存参数和 `ND_*` 凭据由 net-connector 处理。VXLAN 采集的 SSH 参数、设备凭据、并发与报告仍由本 CLI 配置负责。Netdisco 来源与非空静态 devices 互斥。
133
+
134
+ ## 宿主复用已打开会话
135
+
136
+ 已有宿主可以直接使用借用入口,无需创建CLI 的传输适配器:
137
+
138
+ ```ruby
139
+ # native 是宿主已经连接的 NX-OS 原生设备,宿主独占整个采集过程。
140
+ snapshot = nil
141
+ native.with_operation(:vxlan) do
142
+ snapshot = Vxlan::Collector.new.collect_session(
143
+ session: native, target: { host: "192.0.2.10" }, fabric_key: "LAB",
144
+ dimensions: [:configuration, :nve_peers]
145
+ )
146
+ end
147
+ # 会话仍由宿主持有;本方法不打开、关闭、提权或重连。
148
+ ```
149
+
150
+ 这里的 net-connector 适配由 ctx_driver 在该可选依赖已加载时处理;其他驱动会话只需实现 `connected?` 和单命令 `send_commands` 回执协议。
151
+
152
+ 原生连接器负责登录、脚本执行、超时与关闭;vxlan 负责查询顺序、解析和领域观测;正式 CLI 负责清单、并发和报告。没有额外的 VXLAN 连接器类型或转发 API。联网脚本在同一操作租约中完成整台设备采集。借用其他驱动时由宿主提供等价的独占机制。
153
+
154
+ 上例在操作块内登记 snapshot:若退出租约或关闭连接时失败,宿主仍可保留已得事实,并单独报告收尾故障。不要仅在 `Net::Connector.open` 成功返回后才登记事实。自动批量脚本通过 Collector 的生命周期入口保留维度及关闭失败状态。
155
+
156
+ 公共并发可在 `~/.config/net-connector/.env` 只设置一次,例如 `NC_PARALLEL=50`。YAML 的 `parallel` 是显式覆盖;要继续继承公共配置,应省略该字段。`--init` 不把公共并发或内置默认值固化进 YAML,后续公共值调整可直接生效;显式 `--parallel` 或本工具专用并发环境变量仍可初始化独立覆盖。
157
+
158
+ ## 结果与退出码
159
+
160
+ 采集与配置备份共用批次进度组件,进度、异常、结束摘要和报告路径统一写入 stderr。交互终端原地刷新登录/采集/排队、耗时及预计剩余;重定向时每 25 台及最后一台输出进度,异常设备即时提示。`--verbose` 增加逐台结果与安全命令事件;`--quiet` / `--no-progress` 关闭人类进度及摘要。`--json` 单独向 stdout 输出自动化摘要。终端输出故障不会重放设备查询,报告保留 `output_error` 并标记未完成。
161
+
162
+ 报告目录为 `vxlans/<UTC 批次>/`,同秒批次也不覆盖:
163
+
164
+ ```text
165
+ summary.json
166
+ summary.txt
167
+ devices/
168
+ LEAF-01-192.0.2.10.txt
169
+ evidence/
170
+ LEAF-01-192.0.2.10.json
171
+ ```
172
+
173
+ `evidence/` 的逐设备 JSON 保存不可变 Snapshot 的结构化事实、各维度诊断和来源指纹;`devices/` 的文本显示设备身份、记录数及诊断代码。摘要不包含配置事实或命令正文。目录权限 0700、文件权限 0600,逐文件原子发布;单设备完成后立即保存,因此中断仍保留已完成结果,摘要列出 pending 设备。报告写入失败会明确返回错误,不宣称成功。
174
+
175
+ 报告根目录须为真实私有目录(0700),拒绝符号链接及组/其他用户可访问的既有目录;不会自动修改既有权限。文件先同步并原子替换,再同步所在目录;替换后同步失败会标为已提交、持久性未确认,保留文件,不重采设备。新建父目录的断电恢复不在此保证内。
176
+
177
+ 摘要 `completed` 表示已采集结果数,逐台 `report_saved` 表示 JSON/TXT 均保存完成;false 表示保存未确认,可能已有部分文件。报告失败时仍尝试保存 incomplete 摘要并返回2;中断后的摘要再次失败仍返回130,安全错误输出 stderr。`pending` 仅列未登记采集结果的目标,不能把它等同于报告缺失。
178
+
179
+ 调度器或执行过程异常退出时也尝试保存摘要,`execution_error` 只记录异常类型,保留已完成设备及 pending 清单。即使全部设备已有完整报告,执行收尾失败仍标为 incomplete 并返回2。连接器未实际提供会话时,核心采集器将全部请求维度标为 failed(`session_not_opened`),不会以空结果冒充完整证据。
180
+
181
+ `complete` 表示所选证据完整,**不代表 Fabric 健康**。配置关联问题在配置事实的 `review_findings` 中,独立于语法完整性。单设备失败不影响其他目标;断链不自动重放查询,关闭失败仍保留已经采集的事实。核心库本身不写这些报告。
182
+
183
+ | 退出码 | 含义 |
184
+ | --- | --- |
185
+ | 0 | 全部所选证据完整,或帮助/初始化/有效预览 |
186
+ | 1 | 部分/失败证据,或没有匹配设备 |
187
+ | 2 | 参数、配置、可选依赖、清单或报告错误 |
188
+ | 130 | 用户中断;已完成报告保留 |
189
+
190
+ `bundle exec rake` 只运行测试、lint、合成离线示例及新入口帮助,不会因增加联网脚本而自动连接设备。集成测试使用合成回执和本地 PTY,不能替代真实 NX-OS 现场验证。现场 YAML、`.env`、采集报告不进入版本库或安装包。
191
+
192
+ ## 修复建议
193
+
194
+ `vxlan collect` 默认输出逐设备诊断,使用 `--scripts` 可选导出配置建议;`vxlan review --batch DIR` 可离线补生成既有报告的候选配置、条件回退和只读验收命令。导出不会执行变更;聚合计划使用 `apply --plan plan.json --item ID`,必须在真实终端明确确认,配置漂移或失败即停止。详见[修复建议说明](../docs/remediation.md)。
195
+
196
+
197
+ 报告采用 topology 式编排,不生成 Markdown 报告:先读 `summary.txt`,再按设备查看 `devices/*.txt`,候选配置位于 `scripts/*.cfg`。`plan.json` 汇总全部诊断、Fabric 对比和按 ID 索引的增量,`plan.json.sha256` 用于校验;`events.jsonl` 记录审查事件,不代表已经下发。在线采集保留 `evidence/*.json` 原始结构化快照。默认不开启脚本导出,`--scripts` 才生成候选命令;没有候选命令的设备不生成空 cfg。离线审查没有设备会话,不创建伪日志目录。
198
+
199
+ Fabric 的 ACL 比较包含有序规则和引用地址组的成员。对象缺失、为空或语法未支持时不生成补挂计划;同名对象存在成员差异时列出共同成员和差异,需确认权威业务策略。创建 ACL 若还会影响其他接口的既有引用,则阻止单 SVI 下发。网关补齐要求共同业务的 VRF、Anycast 模式和 MAC 一致。历史证据未包含地址组时须重新采集,不能把未知依赖当作一致。
200
+
201
+ `fabric-policy.yml` 显式声明各 Fabric 的 `leaves`、`borders`、`spines`。Leaf 与 Border 按各自已部署的共同 VNI 比较;Spine 检查角色冲突。业务目录联合 VLAN/NVE/EVPN 识别不完整部署,总览显示覆盖范围、未纳入设备和缺证据成员。只有完整一致的对端与本机唯一业务接口相互印证、且全 Fabric 无跨 VNI 网段冲突时,才建议补齐已有 VLAN 的 VNI 关联;不会推导全量铺开 VLAN,也不按命名猜测角色。
202
+
203
+ 每次采集独立合并进程环境与指定 `.env`,不改写调用者环境;凭据、清单与参数使用同一份本次有效环境。Fabric 策略在连接前加载、校验并固定,采集中途修改策略文件只影响下一批。下发只接受带校验文件的 `plan.json` 与 `--item ID`,不接受旧版独立单项计划。
data/bin/vxlan ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # 源码直接执行与 gem 安装入口共用相邻 lib,不依赖启动目录。
5
+ $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
6
+ require "vxlan/cli"
7
+
8
+ exit Vxlan::CLI.run(ARGV)