netstack 0.1.1 → 0.2.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.
Files changed (279) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -3
  3. data/{LICENSE.txt → LICENSE} +7 -6
  4. data/NOTICE +25 -0
  5. data/README.md +58 -20
  6. data/docs/acceptance.md +92 -0
  7. data/docs/backups.md +100 -0
  8. data/docs/configuration.md +198 -0
  9. data/docs/connector.md +187 -0
  10. data/docs/ddi.md +142 -0
  11. data/docs/deployment.md +47 -0
  12. data/docs/foundations.md +45 -0
  13. data/docs/implementation.md +68 -0
  14. data/docs/inventory.md +42 -0
  15. data/docs/monitoring.md +227 -0
  16. data/docs/motor_integration.md +96 -0
  17. data/docs/performance.md +39 -0
  18. data/docs/release.md +20 -0
  19. data/docs/vxlan.md +91 -0
  20. data/docs/wireless.md +81 -0
  21. data/lib/netstack/backups/artifact.rb +23 -0
  22. data/lib/netstack/backups/diff.rb +15 -0
  23. data/lib/netstack/backups/repository.rb +77 -0
  24. data/lib/netstack/backups/request.rb +78 -0
  25. data/lib/netstack/circuits/business_calendar.rb +51 -0
  26. data/lib/netstack/circuits/capacity_review.rb +191 -0
  27. data/lib/netstack/circuits/endpoint.rb +25 -0
  28. data/lib/netstack/circuits/monitoring_plan.rb +212 -0
  29. data/lib/netstack/configuration/artifact.rb +85 -0
  30. data/lib/netstack/configuration/artifact_resolver.rb +30 -0
  31. data/lib/netstack/configuration/bootstrap/payload.rb +67 -0
  32. data/lib/netstack/configuration/bootstrap/validator.rb +224 -0
  33. data/lib/netstack/configuration/catalog.rb +60 -0
  34. data/lib/netstack/configuration/generator.rb +87 -0
  35. data/lib/netstack/configuration/input_contract.rb +82 -0
  36. data/lib/netstack/configuration/payload.rb +168 -0
  37. data/lib/netstack/configuration/reader.rb +124 -0
  38. data/lib/netstack/configuration/support.rb +30 -0
  39. data/lib/netstack/configuration/system_configuration.rb +56 -0
  40. data/lib/netstack/configuration/template_manager.rb +174 -0
  41. data/lib/netstack/configuration/template_store.rb +40 -0
  42. data/lib/netstack/configuration/validator.rb +566 -0
  43. data/lib/netstack/connector/authentication.rb +77 -0
  44. data/lib/netstack/connector/authentication_error.rb +11 -0
  45. data/lib/netstack/connector/backup.rb +19 -0
  46. data/lib/netstack/connector/backup_busy.rb +11 -0
  47. data/lib/netstack/connector/backup_persistence_error.rb +32 -0
  48. data/lib/netstack/connector/command.rb +63 -0
  49. data/lib/netstack/connector/command_result.rb +24 -0
  50. data/lib/netstack/connector/command_timeout.rb +11 -0
  51. data/lib/netstack/connector/configuration.rb +138 -0
  52. data/lib/netstack/connector/connection_closed.rb +11 -0
  53. data/lib/netstack/connector/connection_error.rb +11 -0
  54. data/lib/netstack/connector/device.rb +284 -0
  55. data/lib/netstack/connector/device_error.rb +11 -0
  56. data/lib/netstack/connector/dialogue.rb +55 -0
  57. data/lib/netstack/connector/error.rb +44 -0
  58. data/lib/netstack/connector/error_metadata.rb +58 -0
  59. data/lib/netstack/connector/event.rb +24 -0
  60. data/lib/netstack/connector/execution.rb +110 -0
  61. data/lib/netstack/connector/interaction.rb +55 -0
  62. data/lib/netstack/connector/internal_error.rb +11 -0
  63. data/lib/netstack/connector/known_hosts.rb +128 -0
  64. data/lib/netstack/connector/local_backup.rb +63 -0
  65. data/lib/netstack/connector/log/event.rb +65 -0
  66. data/lib/netstack/connector/log/formatter.rb +18 -0
  67. data/lib/netstack/connector/log/messages.rb +54 -0
  68. data/lib/netstack/connector/log/redacting_writer.rb +33 -0
  69. data/lib/netstack/connector/log/transcript.rb +35 -0
  70. data/lib/netstack/connector/log.rb +262 -0
  71. data/lib/netstack/connector/log_error.rb +11 -0
  72. data/lib/netstack/connector/login_timeout.rb +11 -0
  73. data/lib/netstack/connector/output_limit_exceeded.rb +11 -0
  74. data/lib/netstack/connector/parsing_error.rb +11 -0
  75. data/lib/netstack/connector/profile/builder.rb +238 -0
  76. data/lib/netstack/connector/profile.rb +225 -0
  77. data/lib/netstack/connector/prompt_error.rb +11 -0
  78. data/lib/netstack/connector/recovery.rb +59 -0
  79. data/lib/netstack/connector/redactor.rb +100 -0
  80. data/lib/netstack/connector/response.rb +25 -0
  81. data/lib/netstack/connector/response_reader.rb +140 -0
  82. data/lib/netstack/connector/result.rb +50 -0
  83. data/lib/netstack/connector/running_config/rendered.rb +16 -0
  84. data/lib/netstack/connector/running_config/strategy.rb +28 -0
  85. data/lib/netstack/connector/running_config.rb +113 -0
  86. data/lib/netstack/connector/save_config.rb +23 -0
  87. data/lib/netstack/connector/script.rb +59 -0
  88. data/lib/netstack/connector/script_error.rb +11 -0
  89. data/lib/netstack/connector/script_output_limit_exceeded.rb +11 -0
  90. data/lib/netstack/connector/session.rb +414 -0
  91. data/lib/netstack/connector/session_busy.rb +11 -0
  92. data/lib/netstack/connector/storage/backup_lock.rb +117 -0
  93. data/lib/netstack/connector/storage/private_file.rb +111 -0
  94. data/lib/netstack/connector/storage/safe_file.rb +64 -0
  95. data/lib/netstack/connector/storage/saved_config.rb +76 -0
  96. data/lib/netstack/connector/terminal_renderer.rb +186 -0
  97. data/lib/netstack/connector/terminal_text.rb +32 -0
  98. data/lib/netstack/connector/textfsm.rb +71 -0
  99. data/lib/netstack/connector/tftp/file_upload.rb +53 -0
  100. data/lib/netstack/connector/tftp/strategy.rb +67 -0
  101. data/lib/netstack/connector/tftp.rb +116 -0
  102. data/lib/netstack/connector/tftp_completion_error.rb +36 -0
  103. data/lib/netstack/connector/tftp_receipt.rb +54 -0
  104. data/lib/netstack/connector/tftp_target.rb +65 -0
  105. data/lib/netstack/connector/topology/checkpoint_error.rb +16 -0
  106. data/lib/netstack/connector/topology/deployment_adapter.rb +163 -0
  107. data/lib/netstack/connector/topology/execution_result.rb +34 -0
  108. data/lib/netstack/connector/topology/immediate_strategy.rb +39 -0
  109. data/lib/netstack/connector/topology/interface_description.rb +46 -0
  110. data/lib/netstack/connector/topology/interface_name.rb +60 -0
  111. data/lib/netstack/connector/topology/plan.rb +105 -0
  112. data/lib/netstack/connector/topology/strategy.rb +76 -0
  113. data/lib/netstack/connector/topology.rb +255 -0
  114. data/lib/netstack/connector/transport_error.rb +11 -0
  115. data/lib/netstack/connector/transports.rb +201 -0
  116. data/lib/netstack/connector/underlying_error.rb +25 -0
  117. data/lib/netstack/connector/unsupported_operation.rb +11 -0
  118. data/lib/netstack/connector/vendors/cisco_ios/running_config.rb +22 -0
  119. data/lib/netstack/connector/vendors/cisco_ios/tftp_backup.rb +41 -0
  120. data/lib/netstack/connector/vendors/cisco_ios/topology.rb +54 -0
  121. data/lib/netstack/connector/vendors/cisco_ios.rb +44 -0
  122. data/lib/netstack/connector/vendors/cisco_nxos/running_config.rb +25 -0
  123. data/lib/netstack/connector/vendors/cisco_nxos/tftp_backup.rb +43 -0
  124. data/lib/netstack/connector/vendors/cisco_nxos.rb +51 -0
  125. data/lib/netstack/connector/vendors/h3c/tftp_backup.rb +34 -0
  126. data/lib/netstack/connector/vendors/h3c/topology.rb +72 -0
  127. data/lib/netstack/connector/vendors/h3c.rb +75 -0
  128. data/lib/netstack/connector/vendors/h3c_wireless.rb +13 -0
  129. data/lib/netstack/connector/vendors/hillstone/running_config.rb +16 -0
  130. data/lib/netstack/connector/vendors/hillstone/tftp_backup.rb +55 -0
  131. data/lib/netstack/connector/vendors/hillstone/topology.rb +64 -0
  132. data/lib/netstack/connector/vendors/hillstone.rb +39 -0
  133. data/lib/netstack/connector/vendors/huawei/tftp_backup.rb +26 -0
  134. data/lib/netstack/connector/vendors/huawei.rb +62 -0
  135. data/lib/netstack/connector/vendors/palo_alto/running_config.rb +77 -0
  136. data/lib/netstack/connector/vendors/palo_alto/tftp_backup.rb +49 -0
  137. data/lib/netstack/connector/vendors/palo_alto/topology.rb +77 -0
  138. data/lib/netstack/connector/vendors/palo_alto.rb +39 -0
  139. data/lib/netstack/connector/vendors/radware/running_config.rb +21 -0
  140. data/lib/netstack/connector/vendors/radware/tftp_backup.rb +49 -0
  141. data/lib/netstack/connector/vendors/radware/topology.rb +19 -0
  142. data/lib/netstack/connector/vendors/radware.rb +59 -0
  143. data/lib/netstack/connector/write_timeout.rb +11 -0
  144. data/lib/netstack/connector.rb +32 -0
  145. data/lib/netstack/ddi/applier.rb +107 -0
  146. data/lib/netstack/ddi/deployment.rb +137 -0
  147. data/lib/netstack/ddi/inputs.rb +61 -0
  148. data/lib/netstack/ddi/manager.rb +197 -0
  149. data/lib/netstack/ddi/plan.rb +99 -0
  150. data/lib/netstack/ddi/scope.rb +127 -0
  151. data/lib/netstack/ddi/settings.rb +44 -0
  152. data/lib/netstack/ddi/state.rb +166 -0
  153. data/lib/netstack/deployment/checkpoint_error.rb +14 -0
  154. data/lib/netstack/deployment/cli_adapter.rb +64 -0
  155. data/lib/netstack/deployment/executor.rb +131 -0
  156. data/lib/netstack/deployment/plan.rb +82 -0
  157. data/lib/netstack/deployment/receipt.rb +78 -0
  158. data/lib/netstack/deployment/recovery.rb +19 -0
  159. data/lib/netstack/deployment/step.rb +16 -0
  160. data/lib/netstack/dimension.rb +30 -0
  161. data/lib/netstack/error.rb +14 -0
  162. data/lib/netstack/input_error.rb +9 -0
  163. data/lib/netstack/integrations/bluecat/client.rb +84 -0
  164. data/lib/netstack/integrations/http/client.rb +146 -0
  165. data/lib/netstack/integrations/http/error.rb +10 -0
  166. data/lib/netstack/integrations/http/response.rb +28 -0
  167. data/lib/netstack/integrations/http_delivery/adapter.rb +51 -0
  168. data/lib/netstack/integrations/http_delivery/client.rb +127 -0
  169. data/lib/netstack/integrations/http_delivery/result.rb +27 -0
  170. data/lib/netstack/integrations/oxidized/client.rb +89 -0
  171. data/lib/netstack/integrations/zabbix/client.rb +211 -0
  172. data/lib/netstack/integrations/zabbix/error.rb +10 -0
  173. data/lib/netstack/inventory/address.rb +30 -0
  174. data/lib/netstack/inventory/changes.rb +13 -0
  175. data/lib/netstack/inventory/cli_parser.rb +75 -0
  176. data/lib/netstack/inventory/collector.rb +99 -0
  177. data/lib/netstack/inventory/device.rb +14 -0
  178. data/lib/netstack/inventory/interface.rb +25 -0
  179. data/lib/netstack/inventory/neighbor.rb +15 -0
  180. data/lib/netstack/inventory/reconciler.rb +74 -0
  181. data/lib/netstack/inventory/snapshot.rb +69 -0
  182. data/lib/netstack/inventory/transceiver.rb +23 -0
  183. data/lib/netstack/ipv4.rb +204 -0
  184. data/lib/netstack/ipv6.rb +88 -0
  185. data/lib/netstack/monitoring/applier.rb +179 -0
  186. data/lib/netstack/monitoring/device_plan.rb +23 -0
  187. data/lib/netstack/monitoring/host_plan.rb +152 -0
  188. data/lib/netstack/monitoring/inputs.rb +73 -0
  189. data/lib/netstack/monitoring/measurements.rb +89 -0
  190. data/lib/netstack/monitoring/mutation.rb +37 -0
  191. data/lib/netstack/monitoring/plan.rb +69 -0
  192. data/lib/netstack/monitoring/probe_plan.rb +19 -0
  193. data/lib/netstack/monitoring/state_comparison.rb +37 -0
  194. data/lib/netstack/range_set.rb +181 -0
  195. data/lib/netstack/routing/lookup.rb +46 -0
  196. data/lib/netstack/routing/lookup_result.rb +14 -0
  197. data/lib/netstack/routing/route.rb +32 -0
  198. data/lib/netstack/routing/snapshot.rb +23 -0
  199. data/lib/netstack/target.rb +15 -0
  200. data/lib/netstack/unsupported_capability.rb +9 -0
  201. data/lib/netstack/values.rb +70 -0
  202. data/lib/netstack/version.rb +1 -1
  203. data/lib/netstack/vxlan/auditor.rb +187 -0
  204. data/lib/netstack/vxlan/cisco_nxos/config_parser.rb +327 -0
  205. data/lib/netstack/vxlan/cisco_nxos/deployment_adapter.rb +63 -0
  206. data/lib/netstack/vxlan/cisco_nxos/runtime_parser.rb +182 -0
  207. data/lib/netstack/vxlan/cisco_nxos/segment_renderer.rb +42 -0
  208. data/lib/netstack/vxlan/collector.rb +77 -0
  209. data/lib/netstack/vxlan/fabric.rb +29 -0
  210. data/lib/netstack/vxlan/finding.rb +20 -0
  211. data/lib/netstack/vxlan/node.rb +51 -0
  212. data/lib/netstack/vxlan/route_policy.rb +57 -0
  213. data/lib/netstack/vxlan/runtime_result.rb +24 -0
  214. data/lib/netstack/vxlan/segment.rb +35 -0
  215. data/lib/netstack/vxlan/segment_plan.rb +25 -0
  216. data/lib/netstack/vxlan/segment_planner.rb +156 -0
  217. data/lib/netstack/vxlan/snapshot.rb +34 -0
  218. data/lib/netstack/vxlan/validation.rb +58 -0
  219. data/lib/netstack/vxlan/verifier.rb +52 -0
  220. data/lib/netstack/vxlan/vpc_domain.rb +20 -0
  221. data/lib/netstack/wireless/access_point.rb +12 -0
  222. data/lib/netstack/wireless/ap_group.rb +12 -0
  223. data/lib/netstack/wireless/assessment.rb +13 -0
  224. data/lib/netstack/wireless/assessor.rb +83 -0
  225. data/lib/netstack/wireless/authentication_connection.rb +12 -0
  226. data/lib/netstack/wireless/bss.rb +12 -0
  227. data/lib/netstack/wireless/client.rb +12 -0
  228. data/lib/netstack/wireless/collector.rb +191 -0
  229. data/lib/netstack/wireless/configuration.rb +13 -0
  230. data/lib/netstack/wireless/finding.rb +12 -0
  231. data/lib/netstack/wireless/h3c/config_parser.rb +229 -0
  232. data/lib/netstack/wireless/h3c/lldp_parser.rb +69 -0
  233. data/lib/netstack/wireless/h3c/runtime_parser.rb +240 -0
  234. data/lib/netstack/wireless/huawei/runtime_parser.rb +83 -0
  235. data/lib/netstack/wireless/invalid_snapshot.rb +11 -0
  236. data/lib/netstack/wireless/neighbor.rb +12 -0
  237. data/lib/netstack/wireless/normalizer.rb +90 -0
  238. data/lib/netstack/wireless/parse_result.rb +13 -0
  239. data/lib/netstack/wireless/radio.rb +12 -0
  240. data/lib/netstack/wireless/reconciler.rb +115 -0
  241. data/lib/netstack/wireless/reconciliation.rb +11 -0
  242. data/lib/netstack/wireless/security_policy.rb +12 -0
  243. data/lib/netstack/wireless/service_template.rb +12 -0
  244. data/lib/netstack/wireless/service_template_bindings.rb +56 -0
  245. data/lib/netstack/wireless/snapshot.rb +150 -0
  246. data/lib/netstack/wireless/state.rb +23 -0
  247. data/lib/netstack/wireless/view.rb +154 -0
  248. data/lib/netstack.rb +10 -3
  249. data/resources/configuration/cisco-bootstrap.erb +118 -0
  250. data/resources/configuration/cisco-distributed-gateway.erb +40 -0
  251. data/resources/configuration/cisco-n9k-vpc.erb +62 -0
  252. data/resources/configuration/cisco-server-port.erb +43 -0
  253. data/resources/configuration/h3c-bootstrap.erb +108 -0
  254. data/resources/configuration/h3c-irf.erb +57 -0
  255. data/resources/configuration/h3c-server-port.erb +36 -0
  256. data/resources/configuration/hillstone-ipsec-vpn.erb +68 -0
  257. data/resources/configuration/hillstone-policy.erb +31 -0
  258. data/resources/configuration/paloalto-ipsec-vpn.erb +39 -0
  259. data/resources/configuration/radware-load-balancer.erb +26 -0
  260. data/resources/textfsm/cisco_cdp_neighbors_detail.textfsm +7 -0
  261. data/resources/textfsm/cisco_ios_running_config_interfaces.textfsm +12 -0
  262. data/resources/textfsm/cisco_ios_show_ip_interface_brief.textfsm +7 -0
  263. data/resources/textfsm/h3c_interface_descriptions.textfsm +11 -0
  264. data/resources/textfsm/h3c_lldp_local_first.textfsm +8 -0
  265. data/resources/textfsm/h3c_lldp_name_first.textfsm +8 -0
  266. data/resources/textfsm/hillstone_interface_descriptions.textfsm +11 -0
  267. data/resources/textfsm/hillstone_lldp_neighbors.textfsm +7 -0
  268. data/resources/textfsm/index +8 -0
  269. data/resources/textfsm/palo_alto_interface_descriptions.textfsm +6 -0
  270. data/resources/textfsm/palo_alto_lldp_neighbors.textfsm +11 -0
  271. data/resources/textfsm/radware_port_names.textfsm +13 -0
  272. metadata +588 -27
  273. data/.rubocop.yml +0 -13
  274. data/CODE_OF_CONDUCT.md +0 -84
  275. data/Gemfile +0 -10
  276. data/Gemfile.lock +0 -40
  277. data/Rakefile +0 -8
  278. data/bin/console +0 -15
  279. data/bin/setup +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eddd468b051e3a6fb12facd3f3089ba029bbc6c021adbe3578abfc3c8b50f48e
4
- data.tar.gz: 656e01f7922ea127b8c839b4aeaeb26763d27205326861ca13a4a362e4710196
3
+ metadata.gz: a061a49349ba46f1b10443be9f63d0f33703b101ceb9332f7bdd9b1155c16af7
4
+ data.tar.gz: b1d581a112546d007308ca9ce0300fe51a974c89c998e0d8c718ced72750e7d0
5
5
  SHA512:
6
- metadata.gz: 0e78a867a0c0a80c2d01e29198fe2aafe3520d49ddac6f4ab7b07996451db9d539b65573089d281197ab4f93008a41a92699c1b3e491b00b97e631c37d382cd7
7
- data.tar.gz: 6ee7a999af13ba478903aaa5a36fbb250f75840a897934fc32450bb78cb3f824f02ea28d3af356128e4b9ab040da88c8b2b8a093d77e493ea7ade1f6173b21ea
6
+ metadata.gz: 3b761c5cddf8d87887f4ffac0615fc0e3514e3ebe6d25f185e6fba326d6c4cb6a894348db8fcaf8e334f0a2a56f01eb1b073bdb8c5163488921447fde4d999db
7
+ data.tar.gz: afb5a7bd3f5e2df4ed23e445dea4b1de7df8df7e8590107008ce2dcc134b4018dbf00c23ea427e6f7a511ab4cffc2d80cb5cdc7ce1816912cf46415ebe585bde
data/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
- ## [Unreleased]
1
+ # Changelog
2
2
 
3
- ## [0.1.0] - 2021-10-19
3
+ ## 0.2.0 — 2026-10-01
4
4
 
5
- - Initial release
5
+ - Replace the legacy 0.1.x API with the standalone Netstack API described in README; this is not a drop-in upgrade.
6
+ - Preserve BlueCat password bytes and compare CNAME targets independently of case and the trailing root dot.
7
+ - Reject overlapping H3C bootstrap access/uplink ranges, unordered ranges and authentication ranges outside the access scope.
8
+ - Require global anycast MAC and bound ACL definitions during VXLAN configuration readback.
9
+ - Merge observed wireless blacklist/whitelist fields by MAC without removing unobserved entries.
10
+ - Reject special files when opening device logs without blocking on FIFOs; add Chinese comments for module ownership and recovery contracts.
11
+
12
+ - Harden topology description writes with separate durable change/persist steps, artifact identity checks, raw-result preservation and readback-only recovery of uncertain writes. The unreleased apply API now requires a Deployment plan and host checkpoint/resolver.
13
+ - Preserve expected VXLAN fabric coverage and mark unrecognized runtime/wireless output partial; reconcile service-template bindings by case-insensitive identity with explicit AP precedence.
14
+ - Preserve disabled monitoring ownership and clean up circuit triggers by host/side, including repeated recovery; canonicalize backup IPv6 association and reject malformed DDI CIDRs.
15
+ - Reject invalid optional configuration types and ambiguous numeric syntax, bound template work and known-host lock waiting, and keep sensitive configuration out of inspection and error metadata.
16
+ - Index inventory reconciliation and reuse execution identity within each Executor call, preserving output order and receipt serialization.
17
+
18
+ - Introduce an independent `Netstack` namespace for device connectivity, observations, network business plans and verified execution.
19
+ - Adapt net-connector's single-device sessions, vendor strategies, TextFSM resources, safe backup and redaction contracts; omit Netdisco and fleet orchestration.
20
+ - Reuse ActiveSupport and standard IPAddr; absorb Algosec interval operations and configuration Reader under responsibility-based names.
21
+ - Add typed inventory, routing, wireless, VXLAN, monitoring/circuits, configuration, DDI and backup modules.
22
+ - Separate complete/partial/unsupported observations and host-owned persistence. Require durable checkpoints before remote writes and readback for uncertain execution.
23
+ - Add offline regression, Zeitwerk, lint, package isolation and Ruby/platform CI gates. Live-device and external-service acceptance remain separate.
24
+ - Provide explicit Motor integration for wireless collection, configuration generation/delivery, external backup, and PostgreSQL-backed monitoring/DDI execution with target ownership and durable recovery.
@@ -1,6 +1,7 @@
1
- The MIT License (MIT)
1
+ MIT License
2
2
 
3
- Copyright (c) 2021 TODO: Write your name
3
+ Copyright (c) 2026 netstack contributors
4
+ Copyright (c) 2026 net-connector contributors
4
5
 
5
6
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
7
  of this software and associated documentation files (the "Software"), to deal
@@ -9,13 +10,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
10
  copies of the Software, and to permit persons to whom the Software is
10
11
  furnished to do so, subject to the following conditions:
11
12
 
12
- The above copyright notice and this permission notice shall be included in
13
- all copies or substantial portions of the Software.
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
14
15
 
15
16
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
17
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
18
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
19
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
20
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- THE SOFTWARE.
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
data/NOTICE ADDED
@@ -0,0 +1,25 @@
1
+ Netstack includes adapted device connection code and templates from net-connector.
2
+ Copyright (c) 2026 net-connector contributors. Licensed under the MIT License.
3
+ The original copyright and permission notice is retained in LICENSE.
4
+
5
+ Domain design draws on local Motor and PDK business implementations. Perl APIs,
6
+ Netdisco integrations, and application authentication are not included.
7
+
8
+ RangeSet, IPv4 and Configuration::Reader adapt algorithms from the user's
9
+ algosec-rails/lib/algosec tree. The original project is not a runtime dependency.
10
+ Source SHA-256 at adaptation:
11
+ ipaddr.rb: a1287b0e4e87399dfc4becb38982429136c2fb350829c7de6aacfd2e8069bf68
12
+ set.rb: a2bb791073b930e4931e1333ff74ea804c6d5ea71334415a7a74cbe449625c6d
13
+ config/reader.rb: f93f34f37bff121b8321bdb170b6595e8557b2988b7160f4473746144caf3d57
14
+ Netstack uses Ruby IPAddr and granular ActiveSupport extensions. It introduces
15
+ no global IPAddr or Set patch. Reader uses SHA-256, and bare IPv4 "any" denotes
16
+ the entire IPv4 space; these are intentional new APIs, not compatibility aliases.
17
+
18
+ Configuration scenarios and restricted template syntax adapt Motor's
19
+ backend/app/services/motor/netconf and backend/app/views/netconf implementations.
20
+ The adapted templates are packaged under resources/configuration. Host database,
21
+ Redis, authorization, spreadsheet uploads and notification code are not bundled.
22
+
23
+ Netstack-specific hardening adds durable interface-description execution and safe
24
+ configuration inspection. The source hashes above identify the original adaptation
25
+ inputs, not the current modified library files; attribution remains unchanged.
data/README.md CHANGED
@@ -1,43 +1,81 @@
1
1
  # Netstack
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/netstack`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ Netstack 是独立 Ruby 网络业务库。它从 Motor、PDK 和 net-connector 的现有实现提取设备连接、网络观察、规划、配置生成与执行验证;宿主应用负责身份权限、数据库、凭据、任务队列和执行所有权。
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
5
+ 要求 Ruby 3.4+。运行时复用 ActiveSupport、Ruby IPAddr、Zeitwerk、expect-pty 和 TextFSM,不依赖 Rails、ActiveRecord、PostgreSQL 或 Netdisco。
6
6
 
7
- ## Installation
7
+ ## 使用
8
8
 
9
- Add this line to your application's Gemfile:
9
+ 安装 RubyGems 版本:
10
10
 
11
11
  ```ruby
12
- gem 'netstack'
12
+ gem "netstack", "~> 0.2.0"
13
13
  ```
14
14
 
15
- And then execute:
15
+ 0.2.0 使用本文描述的独立 `Netstack` API,不兼容旧 0.1.x API;升级前需要调整调用代码。开发时也可显式引用本地工作树:
16
16
 
17
- $ bundle install
17
+ ```ruby
18
+ gem "netstack", path: "/path/to/netstack"
19
+ ```
18
20
 
19
- Or install it yourself as:
21
+ ```ruby
22
+ require "netstack"
23
+
24
+ target = Netstack::Target.new(
25
+ key: "leaf-1", host: "192.0.2.10", platform: :cisco_nxos
26
+ )
27
+ snapshot = Netstack::Inventory::Collector.new.collect(
28
+ target: target,
29
+ dimensions: %i[device interfaces],
30
+ connection_options: { username: username, password: password }
31
+ )
32
+
33
+ snapshot.dimensions.each do |name, dimension|
34
+ # 只有 complete 的对应范围可以用于完整替换;其余状态保留旧数据。
35
+ puts "#{name}: #{dimension.status}"
36
+ end
37
+ ```
20
38
 
21
- $ gem install netstack
39
+ 示例地址使用文档网段。真实调用需要显式传入设备、凭据和信任配置;`require "netstack"` 与 `Netstack.eager_load!` 本身不连接外部系统。
22
40
 
23
- ## Usage
41
+ ## 模块分布
24
42
 
25
- TODO: Write usage instructions here
43
+ | 路径 / 命名空间 | 职责 |
44
+ | --- | --- |
45
+ | `connector/` / `Connector` | 单设备 SSH/Telnet 会话、厂商命令、配置备份、邻居、TextFSM |
46
+ | `inventory/` / `Inventory` | 设备、接口、地址、光模块、邻居值对象,CLI 采集及按来源对账 |
47
+ | `routing/` / `Routing` | 路由快照、VRF/地址族隔离、最长前缀、优先级和 ECMP 查询 |
48
+ | `wireless/` / `Wireless` | AP、Radio、BSS、Client、配置与运行状态、完整性和质量评估 |
49
+ | `vxlan/` / `Vxlan` | NX-OS 配置/运行观察、Fabric 审计、Segment 增量规划与验证 |
50
+ | `monitoring/`, `circuits/` | Zabbix 设备/链路监控规划、测量、工作日容量评估 |
51
+ | `configuration/` / `Configuration` | 配置读取、业务输入校验、受限模板、配置工件和场景生成 |
52
+ | `deployment/` / `Deployment` | 版本化计划、持久检查点、执行收据、未知结果恢复 |
53
+ | `ddi/`, `backups/` | DNS/DHCP/IPAM 编排、外部配置备份访问 |
54
+ | `integrations/` | HTTP、Zabbix、BlueCat、Oxidized 与 HTTP 配置交付协议 |
55
+ | `ipv4.rb`, `ipv6.rb`, `range_set.rb` | 标准 IPAddr 上的领域地址与压缩区间运算 |
26
56
 
27
- ## Development
57
+ 文件名对应 Zeitwerk 常量名。持久化与授权不下沉到领域对象;协议差异留在厂商或集成模块中。CLI 不支持的采集维度会明确返回 `unsupported`,不会伪造空的完整快照。
28
58
 
29
- After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
59
+ ## 业务边界
30
60
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
61
+ - 完整、部分、失败、不支持、未请求分别记录。完整性按维度和范围判断,避免部分采集删除有效旧数据。
62
+ - 计划可以离线检查和持久化;执行前必须有宿主的持久意图、目标所有权和同步检查点。
63
+ - 提交、接受、外部效果确认是不同事实。未知执行先只读验证,禁止自动重放不确定 CLI 操作。
64
+ - 接口描述变更也使用 `Deployment::Plan`:配置和保存分别先提交持久检查点;私有命令工件由引用解析并校验 SHA-256。调用方式见 [Connector](docs/connector.md)。
65
+ - 凭据运行时注入;配置原文、备份原文和执行原始输出由宿主按敏感数据管理,不作为普通日志。
66
+ - 不提供 Netdisco 数据库/HTTP 实现、Fleet、专用 CLI、宿主账号/RBAC 或通知发送。
32
67
 
33
- ## Contributing
68
+ 详见 [执行与恢复](docs/deployment.md)、[设备采集与路由](docs/inventory.md)、[基础对象复用](docs/foundations.md)、[Connector](docs/connector.md)、[无线](docs/wireless.md)、[VXLAN](docs/vxlan.md)、[监控](docs/monitoring.md)、[配置生成与交付](docs/configuration.md)、[DDI](docs/ddi.md)、[外部备份](docs/backups.md) 和 [实施记录](docs/implementation.md)。
34
69
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/netstack. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/netstack/blob/master/CODE_OF_CONDUCT.md).
70
+ ## 开发验证
36
71
 
37
- ## License
72
+ ```sh
73
+ bundle install
74
+ bundle exec rake ci
75
+ ```
38
76
 
39
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
77
+ `ci` 包含 eager load、Minitest、RuboCop、gem 构建和独立 GEM_HOME 安装验证。`script/verify_package.rb` 仅使用 Bundler 已解析的本地 gem 缓存;缺失依赖缓存时先执行 `bundle cache`。该验证不访问生产设备、Zabbix、BlueCat 或 Oxidized。
40
78
 
41
- ## Code of Conduct
79
+ CI 配置覆盖 Linux/macOS、Ruby 3.4/4.0。配置矩阵并不代表远端 CI 或真实平台验收已经完成,实际结果见实施记录。Motor 的显式接入入口与独立 bundle 见 [宿主接入](docs/motor_integration.md)。
42
80
 
43
- Everyone interacting in the Netstack project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/netstack/blob/master/CODE_OF_CONDUCT.md).
81
+ 源实现与改编说明见 [NOTICE](NOTICE)。版本变更见 [CHANGELOG](CHANGELOG.md)。
@@ -0,0 +1,92 @@
1
+ # Release acceptance — 0.2.0
2
+
3
+ The release preparation run on macOS arm64 / Ruby 4.0.6 passed
4
+ `bundle exec rake ci`: 675 tests / 7752 assertions, zero failures/errors/skips,
5
+ 307 Ruby files lint clean, eager loading and isolated installation with bundled
6
+ templates. All six follow-up findings have regression coverage observed failing
7
+ before repair and passing afterwards. Host and live-provider validation were not
8
+ rerun; the historical results below do not prove current host integration.
9
+
10
+ Release CI runs Ruby 3.4/4.0 on Ubuntu/macOS. After all four jobs pass, a dedicated
11
+ package job verifies and uploads the exact gem and SHA256SUMS for publication.
12
+ Remote run and artifact provenance are recorded in the GitHub Release.
13
+
14
+ ## Historical review acceptance — 2026-10-01
15
+
16
+ The approved reliability/performance review is implemented in Netstack only. The
17
+ working tree at that checkpoint was uncommitted with no HEAD. Original files were preserved and
18
+ compared with a separate pre-review source snapshot; no Motor files were changed.
19
+
20
+ | Environment | Behavioral suite | Other gates |
21
+ | --- | --- | --- |
22
+ | macOS arm64, Ruby 3.4.11 | 664 tests, 7702 assertions; zero failures/errors/skips | Zeitwerk, 307 Ruby files lint clean, isolated installed gem passed |
23
+ | macOS arm64, Ruby 4.0.7 | 664 tests, 7702 assertions; zero failures/errors/skips | Zeitwerk, 307 Ruby files lint clean, isolated installed gem passed |
24
+
25
+ Both runs executed `bundle exec rake ci`. Ruby 3.4 used the existing isolated
26
+ `BUNDLE_PATH=tmp/ruby34-bundle`. Package verification now also exercises the public
27
+ topology artifact → Deployment plan → checkpointed change/readback/persist API
28
+ from the installed gem, with its bundled templates. New regressions were first
29
+ observed failing against the earlier implementation, then passed after repair.
30
+
31
+ The review fixes incomplete collection coverage, binding/ownership reconciliation,
32
+ checkpointed topology writes, input and diagnostic boundaries, and bounded local
33
+ lock/template work. Cross-review also caught an unknown port-channel member token
34
+ and preserved the existing multiline interface-input contract. Reproducible timing
35
+ and allocation measurements are in [performance.md](performance.md).
36
+
37
+ This review did not rerun Linux/Docker, Motor/PostgreSQL host integration or remote
38
+ CI, and contacted no live device/provider. The older integration results below
39
+ are historical evidence for the original implementation, not revalidation of
40
+ these changes. Host persistence and real-device save confirmation remain separate
41
+ acceptance requirements. No commit, push, publication or deployment was performed.
42
+
43
+ # Original integration acceptance — 2026-09-30
44
+
45
+ The approved implementation is complete in the local working trees. Netstack is an unreleased 0.1.0 gem; this repository has no commit yet. Motor integration adds explicit entrypoints and preserves the existing production dependency source and job/controller defaults.
46
+
47
+ ## Library gates
48
+
49
+ | Environment | Behavioral suite | Other gates |
50
+ | --- | --- | --- |
51
+ | macOS arm64, Ruby 3.4.11 | 614 tests, 7142 assertions; zero failures/errors/skips | Eager load, RuboCop, isolated installed package passed |
52
+ | macOS arm64, Ruby 4.0.7 | 614 tests, 7142 assertions; zero failures/errors/skips | Eager load, RuboCop, isolated installed package passed |
53
+ | Linux aarch64, Ruby 3.4.11, `ruby:3.4-bookworm` | 614 tests, 7142 assertions; zero failures/errors/skips | Eager load, RuboCop, isolated installed package passed |
54
+ | Linux aarch64, Ruby 4.0.7, `ruby:4.0-bookworm` | 614 tests, 7142 assertions; zero failures/errors/skips | Eager load, RuboCop, isolated installed package passed |
55
+
56
+ The project gate is `bundle exec rake ci`. It checks Zeitwerk, the full Minitest suite, 294 Ruby files with RuboCop, and a real `.gem` installed under a fresh GEM_HOME outside the source tree. The installed check loads all constants, parses all TextFSM templates, loads all configuration templates, and rejects Rails/ActiveRecord/Netdisco runtime coupling. The macOS 3.4 final run used the equivalent `rake test lint zeitwerk:check` plus `rake package:verify` separately to avoid concurrent writes to the shared package output.
57
+
58
+ Docker gates use a copied source tree, with the host source mounted read-only. The dependency set includes ActiveSupport 8.1.4, expect-pty 0.6.1 and TextFSM 0.2.0. Package warnings concern the absent homepage and, on older RubyGems, open-ended dependency requirements; no repository URL or unsupported upper version bound was invented to suppress them.
59
+
60
+ ## Motor gates
61
+
62
+ Actual Motor source was copied into a separate container with Ruby 4.0.6, Rails 8.1.3.1, PostgreSQL 18 and Redis 8. `Gemfile.netstack` explicitly selected the local gem. Tests used a dedicated database, not the user's existing database.
63
+
64
+ | Gate | Result |
65
+ | --- | --- |
66
+ | Wireless CLI integration | 17 RSpec examples passed |
67
+ | Configuration generator contract | 16 RSpec examples passed |
68
+ | HTTP delivery through the existing executor | 11 RSpec examples passed |
69
+ | Oxidized repository integration | 5 RSpec examples passed |
70
+ | Durable device monitoring | 17 RSpec examples passed |
71
+ | Durable BlueCat DDI | 17 RSpec examples passed |
72
+ | All six entrypoints in one invocation | 83 examples, zero failures |
73
+ | New/changed integration Ruby files | 17 files, RuboCop clean |
74
+ | Original Motor bundle eager loading | `rails zeitwerk:check` passed without adding Netstack to that bundle |
75
+ | Existing executor and Oxidized behavior under the original bundle | 16 RSpec examples passed |
76
+
77
+ The 34 monitoring/DDI examples commit real transactions. A separate PostgreSQL connection verifies checkpoint visibility before provider writes, active ownership uniqueness, session-lock contention and release, configuration row locks and absence of a transaction during provider I/O. They also cover connection replacement, same-session recursion, delayed checkpoints, endpoint/revision drift, fresh-service recovery, lost receipts and sensitive-data exclusion. Provider responses are controlled fixtures.
78
+
79
+ The new migration was executed against the isolated database. Its generated schema was compared with the existing Motor working schema; only the version, new execution table/constraints and two foreign keys differed. Those generated changes were copied back while preserving prior Motor work. RailsAdmin excludes the execution model from generic CRUD.
80
+
81
+ Motor's runtime set uses ActiveSupport 8.1.3.1 and TextFSM 0.2.1; eager loading and every bundled template also passed under that set. The library's Minitest suite uses its own development bundle. An extra attempt to run it through Motor's RSpec-oriented bundle stopped at the missing `minitest/mock` development dependency before any assertions; Motor dependencies were not changed to disguise that setup mismatch.
82
+
83
+ Reproduction commands and the six explicit spec paths are in [motor_integration.md](motor_integration.md). Motor's own persistence guide is `docs/NETSTACK_EXECUTIONS.md` in its repository.
84
+
85
+ ## Delivery limits
86
+
87
+ - No production devices, Zabbix, BlueCat, Oxidized or HTTP delivery service were contacted. No remote CI run, commit, push, gem publication or production deployment was performed.
88
+ - The OS/version matrix above is local ARM evidence. The GitHub Actions matrix is configured but was not run remotely.
89
+ - Default Motor jobs/controllers have not been switched. A target must leave its old writer before enabling the new durable entrypoints. Authorization, approval, queue scheduling and manual resolution remain host responsibilities.
90
+ - Device/vendor and protocol coverage is stated in each domain document. Unsupported dimensions and uncertain external effects remain explicit; no empty snapshot or accepted request is treated as proof of completion.
91
+
92
+ The implementation and cross-review completion record is [implementation.md](implementation.md); mature-library reuse is documented in [foundations.md](foundations.md).
data/docs/backups.md ADDED
@@ -0,0 +1,100 @@
1
+ # Configuration backups and Oxidized
2
+
3
+ `Integrations::Oxidized::Client` implements node inventory, current configuration,
4
+ version history, selected-version diff and backup queue requests. `Backups::Repository`
5
+ adds target association and version ownership. HTTP defaults verify TLS, enforce
6
+ byte/time budgets and disable redirects and retries. There is no implicit
7
+ Netdisco, Rails, environment configuration or filesystem backup store.
8
+
9
+ ```ruby
10
+ client = Netstack::Integrations::Oxidized::Client.new(base_url: "https://backup.example.test")
11
+ repository = Netstack::Backups::Repository.new(client: client)
12
+ node = repository.node!(target: target, aliases: ["edge.example.test"])
13
+ configuration = repository.configuration(node: node)
14
+ versions = repository.versions(node: node)
15
+ diff = repository.diff(node: node, from_oid: older_oid, to_oid: newer_oid)
16
+ ```
17
+
18
+ Node matching uses explicit target identities and aliases; ambiguity raises an
19
+ error. Version identifiers must be distinct and both belong to the selected
20
+ node. Address matching canonicalizes IPv4/IPv6 notation on both sides; equivalent
21
+ compressed and expanded IPv6 addresses still participate in ambiguity checks.
22
+ Invalid rows are errors, not silently discarded. Node/group path segments
23
+ and query values are encoded separately. `node` returns nil when no match exists;
24
+ `node!` raises `node_not_found`.
25
+
26
+ Configuration and diff return immutable `Artifact`/`Diff` objects. Inspection
27
+ shows only size and SHA-256, and never returns original bytes. Deliberate access
28
+ uses `artifact.content` or `diff.lines`; the host controls authorization,
29
+ encryption, retention, download responses and audit logging. Do not log explicit
30
+ content merely because the wrapper's default inspection is safe. Line endings
31
+ in raw configuration are preserved.
32
+
33
+ ## Requesting and verifying a backup
34
+
35
+ ```ruby
36
+ request = Netstack::Backups::Request.new(repository: repository)
37
+ receipt = request.call(
38
+ target: target, aliases: [], execution_id: execution_id,
39
+ checkpoint: durable_checkpoint
40
+ )
41
+ result = request.recover(
42
+ execution_id: execution_id, events: committed_events,
43
+ checkpoint: durable_checkpoint
44
+ )
45
+ ```
46
+
47
+ The host persists an authorized intent and holds an exclusive execution lock
48
+ before `call`. The callback must synchronously commit the event and return
49
+ literal `true`. `started` precedes the queue request; `receipt` means only that
50
+ Oxidized acknowledged it. Keep the complete event stream under the execution ID;
51
+ recovery rejects events from another execution and never submits another backup.
52
+
53
+ Checkpoints bind the target key/host/platform/serial and the node's name, group, IP,
54
+ full name and model. A same-name node replacement does not confirm the original
55
+ request. Legacy or incomplete checkpoints lacking that fingerprint cannot
56
+ establish completion and require reconciliation.
57
+
58
+ Oxidized Web's `/node/next` is a side-effectful GET and its implementation ignores
59
+ group. Requests therefore require a globally unique node name even if a read
60
+ can be selected by group. An HTTP timeout is an unknown queue result, not an
61
+ instruction to retry. The low-level client's `request_backup` is a transport
62
+ primitive; application writes use `Backups::Request` and the durable checkpoint.
63
+
64
+ Completion requires a fresh successful attempt whose start is on or after the
65
+ recorded request, whose end follows its start, and whose completion differs from
66
+ the baseline. An unchanged configuration can still complete, without requiring
67
+ a new Git commit. Old success, an attempt that started before the request,
68
+ missing timing evidence and an in-progress attempt remain pending. A fresh
69
+ failed attempt raises `backup_failed`. The host schedules polling with a finite
70
+ deadline and preserves unresolved results for reconciliation.
71
+
72
+ This freshness check assumes synchronized host/Oxidized clocks. Oxidized supplies
73
+ no per-request queue ID: fresh successful observation proves a subsequent backup,
74
+ not causal ownership against concurrent scheduled or administrator requests.
75
+ The client accepts ISO 8601 timestamps and upstream's `Time#to_s` UTC serialization;
76
+ invalid timestamps are rejected. No API response is interpreted as a backup
77
+ completion merely because it is HTTP 200.
78
+
79
+ ## Motor integration
80
+
81
+ Motor has an opt-in `Motor::Devices::NetstackRepository` facade at
82
+ `backend/app/services/motor/devices/netstack_repository.rb`. Construct it with a
83
+ real `Netstack::Backups::Repository`; it preserves Motor's read-response shapes
84
+ and enabled configuration control. It exposes checkpoint-requiring backup
85
+ requests and recovery and verifies recovery belongs to the device. Existing
86
+ `OxidizedConfiguration` remains the default path until explicitly migrated.
87
+
88
+ Use Motor's independent `Gemfile.netstack` integration bundle with explicit
89
+ `NETSTACK_PATH`. The integration RSpec exercises the actual gem through HTTP
90
+ fixtures. Motor retains route authorization, encrypted settings, jobs and
91
+ durable execution storage. A test callback collecting events in memory is not
92
+ a production persistence implementation.
93
+
94
+ Offline tests cover node ambiguity, unsafe queue identity, invalid protocol
95
+ rows, version ownership, raw-byte handling, checkpoint failure and stale/fresh
96
+ backup evidence. Motor integration tests validate the facade with its actual
97
+ Rails models and the gem. No live Oxidized service or network device was used.
98
+
99
+ - [Oxidized Web routes and queue behavior](https://github.com/ytti/oxidized-web/blob/master/lib/oxidized/web/webapp.rb)
100
+ - [Oxidized node serialization](https://github.com/ytti/oxidized/blob/master/lib/oxidized/node.rb)
@@ -0,0 +1,198 @@
1
+ # Configuration generation and delivery
2
+
3
+ `Netstack::Configuration` extracts Motor Netconf's input contracts, validation,
4
+ payload construction and 11 safe templates into a Ruby library. It does not own
5
+ users, authorization, encrypted settings, template versions, jobs, artifact storage,
6
+ ZIP archives, email or retention. Those stay in the host application.
7
+
8
+ | Scenario | Vendors | Included behavior |
9
+ | --- | --- | --- |
10
+ | `bootstrap` | H3C, Cisco NX-OS | Management, AAA/TACACS, NTP/DNS/syslog/SNMP, users, security controls; H3C access/aggregation/core and RADIUS admission; NX-OS leaf/spine/border, OSPF underlay, BGP EVPN/NVE, external peers and optional vPC |
11
+ | `h3c-irf` | H3C | Master links, standby renumber/reboot, standby links, BFD MAD addressing and inspection commands |
12
+ | `distributed-gateway` | Cisco NX-OS | VLAN/VNI, EVPN, VRF SVI/gateway/ACL/MTU, NVE BGP replication |
13
+ | `cisco-n9k-vpc` | Cisco NX-OS | Separate primary/secondary roles, keepalive and virtual peer-link, peer port-channel, fabric ports, infrastructure VLAN |
14
+ | `server-port` | H3C, Cisco NX-OS | Standalone/IRF/vPC, access/trunk/ranges, explicit or automatic aggregates and member consistency |
15
+ | `hillstone-policy` | Hillstone | Zones, IPv4/CIDR/ranges/Any, TCP/UDP ports/ranges/Any, address and service groups, ordered permit/deny rules and logging |
16
+ | `load-balancer` | Radware | Real servers, groups, VIP services, proxy IP, port translation, health checks, timeout/persistence and explicit host routing |
17
+ | `ipsec-vpn` | Palo Alto, Hillstone | IKEv1/v2, proposals, vendor crypto options, peer/PSK, subnet cross-product selectors, tunnel, optional routing and DPD |
18
+
19
+ The existing Motor scenario/vendor names and nested input fields are preserved.
20
+ `Catalog.all`, `Catalog.variables_for_template` and `InputContract.fields_for`
21
+ describe them. Cisco templates are NX-OS-specific; they do not advertise IOS support.
22
+ Historical cryptographic options remain expressible for existing configurations;
23
+ the catalog is not a recommendation to choose those algorithms for new tunnels.
24
+
25
+ ## Generate and inspect
26
+
27
+ ```ruby
28
+ require "netstack"
29
+
30
+ artifact = Netstack::Configuration::Generator.call(
31
+ scenario: "distributed-gateway", vendor: "cisco",
32
+ input: { gateways: [{ vlan: 100, subnet: "10.100.0.0/24", vrf: "APP" }] }
33
+ )
34
+ artifact.summary # digest, size, filename, scenario, vendor, timestamp
35
+ artifact.content # explicit access to potentially secret configuration text
36
+ ```
37
+
38
+ Bootstrap requires explicit `system_config:` (or a complete `input[:system]`):
39
+ domain, timezone, management VLAN, NTP/DNS/syslog/TACACS lists and credentials,
40
+ SNMP community, SSH ACLs, local users and security controls. RADIUS is additionally
41
+ required when H3C admission is enabled. Blank secret overrides preserve a saved
42
+ secret only from the supplied defaults; a new username never borrows another
43
+ user's password. `SystemConfiguration.frontend_defaults` removes secret values.
44
+ Only omitted values, `nil` and blank text select optional defaults; `false`, arrays
45
+ and objects are rejected where a text or numeric value is required. Secret overrides
46
+ must be strings even when their optional feature is disabled.
47
+
48
+ H3C access and authentication ranges must use ordered physical ports on the same
49
+ interface type/member/slot. Uplinks must be outside both ranges; the authentication
50
+ range must be inside the access range. Invalid topology fails before rendering.
51
+
52
+ Radware generation requires `settings: { next_hop: "192.0.2.1" }`; its route metric
53
+ defaults to 1 and may be supplied explicitly. The Motor installation's original
54
+ `10.20.0.1` is deliberately not a universal library default. IPsec accepts explicit
55
+ `virtual_router`, `route_metric`, `dpd_interval`, `dpd_retry`, `hillstone_sa_index`
56
+ and `tunnel_zone` in addition to the original Motor fields.
57
+
58
+ For bootstrap batch input, pass `{ devices: [...], system: {...} }`. All devices
59
+ are validated together (including unique hostname and management address) before
60
+ returning a frozen array of individual artifacts. The host may archive them.
61
+ `Generator.new(clock: ...)` supplies deterministic timestamps and policy object names.
62
+
63
+ `h3c-irf` and `cisco-n9k-vpc` also generate their full review document, but that
64
+ document cannot be directly planned for execution. Select the explicit section:
65
+
66
+ ```ruby
67
+ vpc.section("primary") # or secondary
68
+ irf.section("master") # standby-renumber, standby-links, mad
69
+ ```
70
+
71
+ IRF standby renumber contains a reboot. The host schedules the correct physical
72
+ target for each section, accounts for reconnect/renumbering, and supplies verification.
73
+ Automatic rollback, multi-node atomicity, save/commit insertion, and reboot recovery
74
+ are not inferred. Built-in templates preserve their explicit save commands; Radware
75
+ apply and Palo Alto commit are left to the reviewed workflow. A generated script is
76
+ not evidence that a device supports every command or that its runtime converged.
77
+
78
+ ## Templates
79
+
80
+ `TemplateStore.new(overrides: { "h3c-bootstrap.erb" => source })` captures an
81
+ immutable template snapshot. Template digests travel with artifacts. Only catalog
82
+ filenames are accepted; arbitrary file paths are rejected. The `.erb` extension
83
+ denotes a restricted dialect inherited from Motor:
84
+
85
+ ```erb
86
+ <% policies.each do |policy| %>
87
+ <% if policy.log %>log session-end<% else %>no log<% end %>
88
+ description <%= policy.description %>
89
+ <% end %>
90
+ ```
91
+
92
+ Only scalar interpolation, hash paths, array loops and if/else/end are interpreted.
93
+ There is no Ruby evaluation, method dispatch, arbitrary expression, require, or ERB
94
+ engine. Unknown roots, missing fields, malformed blocks and invalid collection types
95
+ fail. Source, output, nesting and rendering work are bounded. The work budget counts
96
+ every visited syntax node and loop iteration, including empty output and empty loop
97
+ bodies. Hosts still authorize template edits: literal text can intentionally contain
98
+ any device command.
99
+ Custom templates must include their appropriate configuration-mode transitions.
100
+
101
+ The validator rejects fractional integer coercion, unknown/duplicate keys, invalid
102
+ address/range/aggregate relationships, nonboolean flags, command control characters,
103
+ and quotes/backslashes in interpolated description/secret fields. Secret values use
104
+ 8–128 printable non-space ASCII characters excluding quotes, backslash, semicolon
105
+ and backtick. Callers receive field-only errors, without input values.
106
+ VLAN lists/ranges, numeric service ports and decimal OSPF areas use decimal syntax;
107
+ leading zeroes are normalized before rendering. Hexadecimal, signed and underscored
108
+ forms are rejected. `Validator#inspect` omits supplied values.
109
+
110
+ ## Durable plans and generic CLI execution
111
+
112
+ ```ruby
113
+ target = Netstack::Target.new(key: "leaf1", host: "192.0.2.10", platform: "cisco_nxos")
114
+ plan = artifact.plan(target: target, artifact_ref: "encrypted-store:artifact-42",
115
+ expected: { vlan: 100, vni: 10100, gateway: "10.100.0.254/24" })
116
+
117
+ adapter = Netstack::Deployment::CliAdapter.new(
118
+ artifact_resolver: ->(reference) { encrypted_store.fetch(reference) },
119
+ preflight: ->(plan:, previous:, credentials:) { identity_and_baseline_match?(plan, previous, credentials) },
120
+ verifier: ->(step:, target:, credentials:, receipt:) { readback_result(step, target, credentials, receipt) }
121
+ )
122
+ receipt = Netstack::Deployment::Executor.new(adapter: adapter).apply(
123
+ plan: plan, execution_id: "operation-42", credentials: connection_credentials,
124
+ checkpoint: ->(event) { durable_store.commit!(event); true }
125
+ )
126
+ ```
127
+
128
+ The checkpoint must commit `event[:receipt]` synchronously before returning exactly
129
+ `true`. The host holds a target lease across the execution/recovery attempt. See
130
+ the deployment contract for restart and lock ownership. The plan contains only
131
+ `artifact_ref` and SHA256, optional request/target identifiers and nonsecret expected
132
+ state. Never put scripts or credentials into expected state, target attributes,
133
+ metadata or checkpoint evidence. Store the Artifact securely, or reconstruct it
134
+ from protected bytes with the same content digest before resolving a reference.
135
+
136
+ CLI commands and outputs are marked sensitive. Comments/blank lines are omitted,
137
+ host is pinned to `Target#host`, and there is no implicit write retry. A successful
138
+ transport is `applied`; the verifier must return `verified`, `failed`, `unknown` or
139
+ `not_applied` with bounded nonsecret evidence. Partial writes are unknown. Resuming
140
+ started/unknown work invokes readback, never a second script submission, and does
141
+ not need to reload an already submitted artifact.
142
+
143
+ For an existing reviewed manual script, including Huawei or Cisco IOS:
144
+
145
+ ```ruby
146
+ manual = Netstack::Configuration::Artifact.script(target: target, content: reviewed_script)
147
+ ```
148
+
149
+ This artifact binds to that target's key, address and platform. It carries no template
150
+ digest and cannot be moved to another target by changing the plan. Manual scripts
151
+ must include their own CLI mode transitions and save/commit decisions. HTTP delivery
152
+ may use platforms supported by the external service; CLI uses Connector's platforms.
153
+
154
+ ## HTTP delivery
155
+
156
+ ```ruby
157
+ http = Netstack::Integrations::Http::Client.new(base_url: endpoint)
158
+ client = Netstack::Integrations::HttpDelivery::Client.new(http: http, lookup_path: "lookup")
159
+ adapter = Netstack::Integrations::HttpDelivery::Adapter.new(
160
+ client: client, artifact_resolver: ->(reference) { encrypted_store.fetch(reference) }
161
+ )
162
+ ```
163
+
164
+ POST retains Motor's `request_no`, `target_id`, `idempotency_key`, `device`,
165
+ `credentials: { username:, password: }` and `script` fields and the
166
+ `Idempotency-Key` header. Target attributes may provide the existing snapshot fields
167
+ `id`, `serial`, `name`, `hostname`, `vendor`, `model`, `os`, `device_role`, `source`;
168
+ the IP always comes from the target. Unrelated attributes are omitted.
169
+
170
+ GET `<endpoint>/<encoded remote id>` reads an acknowledged task. An uncertain POST
171
+ with no remote id instead uses GET `lookup_path?idempotency_key=<original key>`;
172
+ the default lookup path is the submission endpoint. `lookup_parameter:` is configurable.
173
+ The key-lookup response **must echo the same `idempotency_key`**. A missing key,
174
+ wrong task, unsupported status, timeout or 404 remains unknown. The remote service
175
+ must durably index each idempotency key and return that operation's terminal result;
176
+ if it cannot, the adapter cannot safely reconcile the uncertainty.
177
+
178
+ `success/succeeded/completed`, `failed/error/rejected`, and
179
+ `accepted/pending/queued/running/processing` are normalized; absent status accepts
180
+ only strict boolean `success`. No automatic POST retry, redirect, or polling loop
181
+ is added. The host schedules subsequent Executor calls with the previous receipt.
182
+ `verified` here proves the remote service reported completion of the identified
183
+ operation; it does not independently prove device running-state convergence.
184
+ Raw remote output is available through `Result#output`, excluded from `inspect` and
185
+ checkpoints. Failure checkpoints use a fixed local error code, not server messages.
186
+
187
+ ## Validation and sources
188
+
189
+ Offline tests cover all 11 templates; bootstrap roles/admission/batches, IRF/vPC
190
+ sections, gateway and aggregate conflicts, policy objects, Radware grouping, both
191
+ VPN vendors/IKE versions, safe template negative cases, artifact digest changes,
192
+ sensitive CLI commands, checkpoint-before-write and unknown HTTP reconciliation.
193
+ No real device or delivery service is exercised by these tests.
194
+
195
+ Business sources: Motor `app/services/motor/netconf/{catalog,input_contract,validator,
196
+ payload,template_manager,bootstrap/*}.rb`, its `app/views/netconf/*.erb` templates,
197
+ and `lib/motor/api/netconf_delivery_client.rb`. The host's original persistence and
198
+ retry implementation is not copied into the library.