pvectl 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 (558) hide show
  1. checksums.yaml +7 -0
  2. data/.claude/rules/branch-before-changes.md +52 -0
  3. data/.claude/rules/documentation-updates.md +104 -0
  4. data/.claude/rules/git-workflow.md +84 -0
  5. data/.claude/rules/proxmox-api-docs.md +58 -0
  6. data/.claude/rules/rbs-signatures.md +80 -0
  7. data/.claude/rules/refactoring-as-design-option.md +35 -0
  8. data/.claude/scheduled_tasks.lock +1 -0
  9. data/.claude/settings.json +51 -0
  10. data/.mcp.json +8 -0
  11. data/.ruby-gemset +1 -0
  12. data/.ruby-version +1 -0
  13. data/CHANGELOG.md +138 -0
  14. data/CLAUDE.md +211 -0
  15. data/CODE_OF_CONDUCT.md +132 -0
  16. data/LICENSE.txt +21 -0
  17. data/README.md +143 -0
  18. data/Rakefile +8 -0
  19. data/docs/proxmox-api-update.sh +96 -0
  20. data/exe/pvectl +5 -0
  21. data/lib/pvectl/argv_preprocessor.rb +334 -0
  22. data/lib/pvectl/cli.rb +102 -0
  23. data/lib/pvectl/commands/apt.rb +389 -0
  24. data/lib/pvectl/commands/clone_container.rb +230 -0
  25. data/lib/pvectl/commands/clone_vm.rb +331 -0
  26. data/lib/pvectl/commands/cloudinit/command.rb +122 -0
  27. data/lib/pvectl/commands/cloudinit/dump.rb +94 -0
  28. data/lib/pvectl/commands/cloudinit/pending.rb +137 -0
  29. data/lib/pvectl/commands/cloudinit/regenerate.rb +79 -0
  30. data/lib/pvectl/commands/config/command.rb +65 -0
  31. data/lib/pvectl/commands/config/get_contexts.rb +68 -0
  32. data/lib/pvectl/commands/config/set_cluster.rb +103 -0
  33. data/lib/pvectl/commands/config/set_context.rb +136 -0
  34. data/lib/pvectl/commands/config/set_credentials.rb +181 -0
  35. data/lib/pvectl/commands/config/use_context.rb +69 -0
  36. data/lib/pvectl/commands/config/view.rb +67 -0
  37. data/lib/pvectl/commands/console.rb +93 -0
  38. data/lib/pvectl/commands/console_ct.rb +187 -0
  39. data/lib/pvectl/commands/console_vm.rb +187 -0
  40. data/lib/pvectl/commands/container_lifecycle_command.rb +77 -0
  41. data/lib/pvectl/commands/create_backup.rb +173 -0
  42. data/lib/pvectl/commands/create_container.rb +141 -0
  43. data/lib/pvectl/commands/create_resource_command.rb +244 -0
  44. data/lib/pvectl/commands/create_snapshot.rb +242 -0
  45. data/lib/pvectl/commands/create_vm.rb +267 -0
  46. data/lib/pvectl/commands/delete_backup.rb +139 -0
  47. data/lib/pvectl/commands/delete_command.rb +119 -0
  48. data/lib/pvectl/commands/delete_container.rb +30 -0
  49. data/lib/pvectl/commands/delete_snapshot.rb +248 -0
  50. data/lib/pvectl/commands/delete_vm.rb +127 -0
  51. data/lib/pvectl/commands/describe/command.rb +251 -0
  52. data/lib/pvectl/commands/edit_container.rb +56 -0
  53. data/lib/pvectl/commands/edit_dns.rb +149 -0
  54. data/lib/pvectl/commands/edit_hosts.rb +135 -0
  55. data/lib/pvectl/commands/edit_node.rb +54 -0
  56. data/lib/pvectl/commands/edit_resource_command.rb +180 -0
  57. data/lib/pvectl/commands/edit_vm.rb +154 -0
  58. data/lib/pvectl/commands/edit_volume.rb +189 -0
  59. data/lib/pvectl/commands/feature_command.rb +230 -0
  60. data/lib/pvectl/commands/feature_container.rb +21 -0
  61. data/lib/pvectl/commands/feature_vm.rb +94 -0
  62. data/lib/pvectl/commands/get/command.rb +360 -0
  63. data/lib/pvectl/commands/get/handlers/backups.rb +76 -0
  64. data/lib/pvectl/commands/get/handlers/capabilities.rb +107 -0
  65. data/lib/pvectl/commands/get/handlers/containers.rb +148 -0
  66. data/lib/pvectl/commands/get/handlers/disks.rb +107 -0
  67. data/lib/pvectl/commands/get/handlers/dns.rb +94 -0
  68. data/lib/pvectl/commands/get/handlers/hosts.rb +94 -0
  69. data/lib/pvectl/commands/get/handlers/nodes.rb +162 -0
  70. data/lib/pvectl/commands/get/handlers/services.rb +81 -0
  71. data/lib/pvectl/commands/get/handlers/snapshots.rb +97 -0
  72. data/lib/pvectl/commands/get/handlers/storage.rb +118 -0
  73. data/lib/pvectl/commands/get/handlers/subscription.rb +69 -0
  74. data/lib/pvectl/commands/get/handlers/tasks.rb +89 -0
  75. data/lib/pvectl/commands/get/handlers/templates.rb +175 -0
  76. data/lib/pvectl/commands/get/handlers/time.rb +118 -0
  77. data/lib/pvectl/commands/get/handlers/vms.rb +145 -0
  78. data/lib/pvectl/commands/get/handlers/volume.rb +134 -0
  79. data/lib/pvectl/commands/get/resource_handler.rb +63 -0
  80. data/lib/pvectl/commands/get/resource_registry.rb +18 -0
  81. data/lib/pvectl/commands/get/watch_loop.rb +129 -0
  82. data/lib/pvectl/commands/irreversible_command.rb +265 -0
  83. data/lib/pvectl/commands/logs/command.rb +275 -0
  84. data/lib/pvectl/commands/logs/handlers/journal.rb +46 -0
  85. data/lib/pvectl/commands/logs/handlers/syslog.rb +53 -0
  86. data/lib/pvectl/commands/logs/handlers/task_detail.rb +52 -0
  87. data/lib/pvectl/commands/logs/handlers/task_logs.rb +115 -0
  88. data/lib/pvectl/commands/logs/resource_handler.rb +46 -0
  89. data/lib/pvectl/commands/logs/resource_registry.rb +22 -0
  90. data/lib/pvectl/commands/migrate_command.rb +282 -0
  91. data/lib/pvectl/commands/migrate_container.rb +23 -0
  92. data/lib/pvectl/commands/migrate_vm.rb +122 -0
  93. data/lib/pvectl/commands/move_disk_command.rb +239 -0
  94. data/lib/pvectl/commands/move_disk_container.rb +21 -0
  95. data/lib/pvectl/commands/move_disk_vm.rb +127 -0
  96. data/lib/pvectl/commands/ping.rb +249 -0
  97. data/lib/pvectl/commands/pull.rb +342 -0
  98. data/lib/pvectl/commands/push.rb +352 -0
  99. data/lib/pvectl/commands/reset.rb +64 -0
  100. data/lib/pvectl/commands/resource_lifecycle_command.rb +277 -0
  101. data/lib/pvectl/commands/resource_registry.rb +73 -0
  102. data/lib/pvectl/commands/restart.rb +70 -0
  103. data/lib/pvectl/commands/restart_container.rb +18 -0
  104. data/lib/pvectl/commands/restore_backup.rb +236 -0
  105. data/lib/pvectl/commands/resume.rb +57 -0
  106. data/lib/pvectl/commands/rollback_snapshot.rb +228 -0
  107. data/lib/pvectl/commands/sendkey_vm.rb +205 -0
  108. data/lib/pvectl/commands/service.rb +293 -0
  109. data/lib/pvectl/commands/set_container.rb +50 -0
  110. data/lib/pvectl/commands/set_node.rb +52 -0
  111. data/lib/pvectl/commands/set_resource_command.rb +185 -0
  112. data/lib/pvectl/commands/set_vm.rb +136 -0
  113. data/lib/pvectl/commands/set_volume.rb +212 -0
  114. data/lib/pvectl/commands/shared_config_parsers.rb +126 -0
  115. data/lib/pvectl/commands/shared_flags.rb +155 -0
  116. data/lib/pvectl/commands/shutdown.rb +73 -0
  117. data/lib/pvectl/commands/shutdown_container.rb +18 -0
  118. data/lib/pvectl/commands/start.rb +79 -0
  119. data/lib/pvectl/commands/start_container.rb +18 -0
  120. data/lib/pvectl/commands/stop.rb +75 -0
  121. data/lib/pvectl/commands/stop_container.rb +18 -0
  122. data/lib/pvectl/commands/suspend.rb +64 -0
  123. data/lib/pvectl/commands/template_command.rb +205 -0
  124. data/lib/pvectl/commands/template_container.rb +27 -0
  125. data/lib/pvectl/commands/template_vm.rb +106 -0
  126. data/lib/pvectl/commands/top/command.rb +206 -0
  127. data/lib/pvectl/commands/top/handlers/containers.rb +61 -0
  128. data/lib/pvectl/commands/top/handlers/nodes.rb +61 -0
  129. data/lib/pvectl/commands/top/handlers/vms.rb +61 -0
  130. data/lib/pvectl/commands/top/resource_handler.rb +46 -0
  131. data/lib/pvectl/commands/top/resource_registry.rb +22 -0
  132. data/lib/pvectl/commands/unlink_disk_vm.rb +232 -0
  133. data/lib/pvectl/commands/vm_lifecycle_command.rb +77 -0
  134. data/lib/pvectl/commands/wakeonlan_node.rb +153 -0
  135. data/lib/pvectl/config/errors.rb +62 -0
  136. data/lib/pvectl/config/models/cluster.rb +180 -0
  137. data/lib/pvectl/config/models/context.rb +100 -0
  138. data/lib/pvectl/config/models/resolved_config.rb +171 -0
  139. data/lib/pvectl/config/models/user.rb +133 -0
  140. data/lib/pvectl/config/provider.rb +297 -0
  141. data/lib/pvectl/config/service.rb +300 -0
  142. data/lib/pvectl/config/store.rb +161 -0
  143. data/lib/pvectl/config/wizard.rb +309 -0
  144. data/lib/pvectl/config_serializer.rb +1034 -0
  145. data/lib/pvectl/connection/retry_handler.rb +161 -0
  146. data/lib/pvectl/connection.rb +157 -0
  147. data/lib/pvectl/console/terminal_session.rb +449 -0
  148. data/lib/pvectl/editor_session.rb +157 -0
  149. data/lib/pvectl/exit_codes.rb +43 -0
  150. data/lib/pvectl/formatters/base.rb +55 -0
  151. data/lib/pvectl/formatters/color_support.rb +90 -0
  152. data/lib/pvectl/formatters/json.rb +45 -0
  153. data/lib/pvectl/formatters/output_helper.rb +77 -0
  154. data/lib/pvectl/formatters/registry.rb +72 -0
  155. data/lib/pvectl/formatters/table.rb +235 -0
  156. data/lib/pvectl/formatters/wide.rb +93 -0
  157. data/lib/pvectl/formatters/yaml.rb +49 -0
  158. data/lib/pvectl/manifest_serializer.rb +142 -0
  159. data/lib/pvectl/models/apt_package.rb +107 -0
  160. data/lib/pvectl/models/backup.rb +173 -0
  161. data/lib/pvectl/models/base.rb +49 -0
  162. data/lib/pvectl/models/capability.rb +62 -0
  163. data/lib/pvectl/models/container.rb +205 -0
  164. data/lib/pvectl/models/container_operation_result.rb +27 -0
  165. data/lib/pvectl/models/dns_config.rb +54 -0
  166. data/lib/pvectl/models/hosts_file.rb +47 -0
  167. data/lib/pvectl/models/journal_entry.rb +16 -0
  168. data/lib/pvectl/models/network_interface.rb +85 -0
  169. data/lib/pvectl/models/node.rb +195 -0
  170. data/lib/pvectl/models/node_operation_result.rb +45 -0
  171. data/lib/pvectl/models/operation_result.rb +110 -0
  172. data/lib/pvectl/models/physical_disk.rb +193 -0
  173. data/lib/pvectl/models/service.rb +80 -0
  174. data/lib/pvectl/models/snapshot.rb +101 -0
  175. data/lib/pvectl/models/snapshot_description.rb +39 -0
  176. data/lib/pvectl/models/storage.rb +180 -0
  177. data/lib/pvectl/models/subscription.rb +87 -0
  178. data/lib/pvectl/models/syslog_entry.rb +17 -0
  179. data/lib/pvectl/models/task.rb +95 -0
  180. data/lib/pvectl/models/task_entry.rb +52 -0
  181. data/lib/pvectl/models/task_log_line.rb +17 -0
  182. data/lib/pvectl/models/time_config.rb +47 -0
  183. data/lib/pvectl/models/vm.rb +137 -0
  184. data/lib/pvectl/models/vm_operation_result.rb +27 -0
  185. data/lib/pvectl/models/volume.rb +133 -0
  186. data/lib/pvectl/models/volume_operation_result.rb +26 -0
  187. data/lib/pvectl/parsers/cloud_init_config.rb +92 -0
  188. data/lib/pvectl/parsers/disk_config.rb +97 -0
  189. data/lib/pvectl/parsers/lxc_mount_config.rb +98 -0
  190. data/lib/pvectl/parsers/lxc_net_config.rb +97 -0
  191. data/lib/pvectl/parsers/net_config.rb +95 -0
  192. data/lib/pvectl/parsers/smart_text.rb +42 -0
  193. data/lib/pvectl/plugin_loader.rb +157 -0
  194. data/lib/pvectl/presenters/apt_package.rb +99 -0
  195. data/lib/pvectl/presenters/backup.rb +128 -0
  196. data/lib/pvectl/presenters/base.rb +283 -0
  197. data/lib/pvectl/presenters/capability.rb +104 -0
  198. data/lib/pvectl/presenters/config/context.rb +80 -0
  199. data/lib/pvectl/presenters/container.rb +574 -0
  200. data/lib/pvectl/presenters/container_operation_result.rb +109 -0
  201. data/lib/pvectl/presenters/disk.rb +184 -0
  202. data/lib/pvectl/presenters/dns_config.rb +68 -0
  203. data/lib/pvectl/presenters/hosts_file.rb +61 -0
  204. data/lib/pvectl/presenters/journal_entry.rb +20 -0
  205. data/lib/pvectl/presenters/node.rb +762 -0
  206. data/lib/pvectl/presenters/node_operation_result.rb +50 -0
  207. data/lib/pvectl/presenters/operation_result.rb +61 -0
  208. data/lib/pvectl/presenters/service.rb +76 -0
  209. data/lib/pvectl/presenters/snapshot.rb +239 -0
  210. data/lib/pvectl/presenters/snapshot_operation_result.rb +125 -0
  211. data/lib/pvectl/presenters/storage.rb +329 -0
  212. data/lib/pvectl/presenters/subscription.rb +189 -0
  213. data/lib/pvectl/presenters/syslog_entry.rb +20 -0
  214. data/lib/pvectl/presenters/task_entry.rb +69 -0
  215. data/lib/pvectl/presenters/task_log_line.rb +20 -0
  216. data/lib/pvectl/presenters/template.rb +76 -0
  217. data/lib/pvectl/presenters/time_config.rb +86 -0
  218. data/lib/pvectl/presenters/top_container.rb +112 -0
  219. data/lib/pvectl/presenters/top_node.rb +115 -0
  220. data/lib/pvectl/presenters/top_presenter.rb +59 -0
  221. data/lib/pvectl/presenters/top_vm.rb +105 -0
  222. data/lib/pvectl/presenters/vm.rb +853 -0
  223. data/lib/pvectl/presenters/vm_operation_result.rb +109 -0
  224. data/lib/pvectl/presenters/volume.rb +136 -0
  225. data/lib/pvectl/presenters/volume_operation_result.rb +58 -0
  226. data/lib/pvectl/repositories/apt.rb +93 -0
  227. data/lib/pvectl/repositories/backup.rb +186 -0
  228. data/lib/pvectl/repositories/base.rb +110 -0
  229. data/lib/pvectl/repositories/capabilities.rb +96 -0
  230. data/lib/pvectl/repositories/container.rb +503 -0
  231. data/lib/pvectl/repositories/disk.rb +87 -0
  232. data/lib/pvectl/repositories/dns.rb +54 -0
  233. data/lib/pvectl/repositories/hosts.rb +63 -0
  234. data/lib/pvectl/repositories/journal.rb +23 -0
  235. data/lib/pvectl/repositories/node.rb +537 -0
  236. data/lib/pvectl/repositories/service.rb +139 -0
  237. data/lib/pvectl/repositories/snapshot.rb +133 -0
  238. data/lib/pvectl/repositories/storage.rb +302 -0
  239. data/lib/pvectl/repositories/subscription.rb +77 -0
  240. data/lib/pvectl/repositories/syslog.rb +25 -0
  241. data/lib/pvectl/repositories/task.rb +82 -0
  242. data/lib/pvectl/repositories/task_list.rb +30 -0
  243. data/lib/pvectl/repositories/task_log.rb +31 -0
  244. data/lib/pvectl/repositories/time_config.rb +53 -0
  245. data/lib/pvectl/repositories/vm.rb +616 -0
  246. data/lib/pvectl/repositories/volume.rb +306 -0
  247. data/lib/pvectl/selectors/base.rb +201 -0
  248. data/lib/pvectl/selectors/container.rb +116 -0
  249. data/lib/pvectl/selectors/disk.rb +59 -0
  250. data/lib/pvectl/selectors/vm.rb +116 -0
  251. data/lib/pvectl/selectors/volume.rb +59 -0
  252. data/lib/pvectl/services/backup.rb +209 -0
  253. data/lib/pvectl/services/clone_container.rb +260 -0
  254. data/lib/pvectl/services/clone_vm.rb +265 -0
  255. data/lib/pvectl/services/cloudinit.rb +96 -0
  256. data/lib/pvectl/services/console.rb +152 -0
  257. data/lib/pvectl/services/container_lifecycle.rb +124 -0
  258. data/lib/pvectl/services/create_container.rb +179 -0
  259. data/lib/pvectl/services/create_vm.rb +191 -0
  260. data/lib/pvectl/services/edit_container.rb +125 -0
  261. data/lib/pvectl/services/edit_dns.rb +159 -0
  262. data/lib/pvectl/services/edit_hosts.rb +78 -0
  263. data/lib/pvectl/services/edit_node.rb +147 -0
  264. data/lib/pvectl/services/edit_vm.rb +125 -0
  265. data/lib/pvectl/services/edit_volume.rb +224 -0
  266. data/lib/pvectl/services/get/resource_service.rb +98 -0
  267. data/lib/pvectl/services/move_disk.rb +132 -0
  268. data/lib/pvectl/services/pull_config.rb +94 -0
  269. data/lib/pvectl/services/push_config.rb +524 -0
  270. data/lib/pvectl/services/resize_volume.rb +253 -0
  271. data/lib/pvectl/services/resource_delete.rb +169 -0
  272. data/lib/pvectl/services/resource_migration.rb +170 -0
  273. data/lib/pvectl/services/sendkey.rb +108 -0
  274. data/lib/pvectl/services/service_lifecycle.rb +89 -0
  275. data/lib/pvectl/services/set_container.rb +128 -0
  276. data/lib/pvectl/services/set_node.rb +236 -0
  277. data/lib/pvectl/services/set_vm.rb +128 -0
  278. data/lib/pvectl/services/set_volume.rb +126 -0
  279. data/lib/pvectl/services/snapshot.rb +261 -0
  280. data/lib/pvectl/services/task_listing.rb +75 -0
  281. data/lib/pvectl/services/unlink_disk.rb +86 -0
  282. data/lib/pvectl/services/vm_lifecycle.rb +124 -0
  283. data/lib/pvectl/services/wakeonlan.rb +79 -0
  284. data/lib/pvectl/utils/resource_resolver.rb +80 -0
  285. data/lib/pvectl/version.rb +13 -0
  286. data/lib/pvectl/wizards/create_container.rb +105 -0
  287. data/lib/pvectl/wizards/create_vm.rb +98 -0
  288. data/lib/pvectl.rb +439 -0
  289. data/sig/external/gli.rbs +16 -0
  290. data/sig/external/proxmox_api.rbs +10 -0
  291. data/sig/pvectl/argv_preprocessor.rbs +53 -0
  292. data/sig/pvectl/cli.rbs +26 -0
  293. data/sig/pvectl/commands/apt.rbs +47 -0
  294. data/sig/pvectl/commands/clone_container.rbs +31 -0
  295. data/sig/pvectl/commands/clone_vm.rbs +33 -0
  296. data/sig/pvectl/commands/cloudinit/command.rbs +13 -0
  297. data/sig/pvectl/commands/cloudinit/dump.rbs +13 -0
  298. data/sig/pvectl/commands/cloudinit/pending.rbs +17 -0
  299. data/sig/pvectl/commands/cloudinit/regenerate.rbs +11 -0
  300. data/sig/pvectl/commands/config/command.rbs +9 -0
  301. data/sig/pvectl/commands/config/get_contexts.rbs +11 -0
  302. data/sig/pvectl/commands/config/set_cluster.rbs +11 -0
  303. data/sig/pvectl/commands/config/set_context.rbs +15 -0
  304. data/sig/pvectl/commands/config/set_credentials.rbs +15 -0
  305. data/sig/pvectl/commands/config/use_context.rbs +11 -0
  306. data/sig/pvectl/commands/config/view.rbs +11 -0
  307. data/sig/pvectl/commands/console.rbs +9 -0
  308. data/sig/pvectl/commands/console_ct.rbs +27 -0
  309. data/sig/pvectl/commands/console_vm.rbs +27 -0
  310. data/sig/pvectl/commands/container_lifecycle_command.rbs +25 -0
  311. data/sig/pvectl/commands/create_backup.rbs +29 -0
  312. data/sig/pvectl/commands/create_container.rbs +30 -0
  313. data/sig/pvectl/commands/create_resource_command.rbs +53 -0
  314. data/sig/pvectl/commands/create_snapshot.rbs +35 -0
  315. data/sig/pvectl/commands/create_vm.rbs +30 -0
  316. data/sig/pvectl/commands/delete_backup.rbs +25 -0
  317. data/sig/pvectl/commands/delete_command.rbs +45 -0
  318. data/sig/pvectl/commands/delete_container.rbs +11 -0
  319. data/sig/pvectl/commands/delete_snapshot.rbs +35 -0
  320. data/sig/pvectl/commands/delete_vm.rbs +13 -0
  321. data/sig/pvectl/commands/describe/command.rbs +27 -0
  322. data/sig/pvectl/commands/edit_container.rbs +17 -0
  323. data/sig/pvectl/commands/edit_dns.rbs +25 -0
  324. data/sig/pvectl/commands/edit_hosts.rbs +23 -0
  325. data/sig/pvectl/commands/edit_node.rbs +17 -0
  326. data/sig/pvectl/commands/edit_resource_command.rbs +35 -0
  327. data/sig/pvectl/commands/edit_vm.rbs +19 -0
  328. data/sig/pvectl/commands/edit_volume.rbs +24 -0
  329. data/sig/pvectl/commands/feature_command.rbs +43 -0
  330. data/sig/pvectl/commands/feature_container.rbs +10 -0
  331. data/sig/pvectl/commands/feature_vm.rbs +12 -0
  332. data/sig/pvectl/commands/get/command.rbs +42 -0
  333. data/sig/pvectl/commands/get/handlers/backups.rbs +23 -0
  334. data/sig/pvectl/commands/get/handlers/capabilities.rbs +29 -0
  335. data/sig/pvectl/commands/get/handlers/containers.rbs +35 -0
  336. data/sig/pvectl/commands/get/handlers/disks.rbs +27 -0
  337. data/sig/pvectl/commands/get/handlers/dns.rbs +25 -0
  338. data/sig/pvectl/commands/get/handlers/hosts.rbs +25 -0
  339. data/sig/pvectl/commands/get/handlers/nodes.rbs +33 -0
  340. data/sig/pvectl/commands/get/handlers/services.rbs +23 -0
  341. data/sig/pvectl/commands/get/handlers/snapshots.rbs +27 -0
  342. data/sig/pvectl/commands/get/handlers/storage.rbs +25 -0
  343. data/sig/pvectl/commands/get/handlers/subscription.rbs +25 -0
  344. data/sig/pvectl/commands/get/handlers/tasks.rbs +28 -0
  345. data/sig/pvectl/commands/get/handlers/templates.rbs +35 -0
  346. data/sig/pvectl/commands/get/handlers/time.rbs +29 -0
  347. data/sig/pvectl/commands/get/handlers/vms.rbs +35 -0
  348. data/sig/pvectl/commands/get/handlers/volume.rbs +27 -0
  349. data/sig/pvectl/commands/get/resource_handler.rbs +13 -0
  350. data/sig/pvectl/commands/get/resource_registry.rbs +8 -0
  351. data/sig/pvectl/commands/get/watch_loop.rbs +33 -0
  352. data/sig/pvectl/commands/irreversible_command.rbs +32 -0
  353. data/sig/pvectl/commands/logs/command.rbs +35 -0
  354. data/sig/pvectl/commands/logs/handlers/journal.rbs +21 -0
  355. data/sig/pvectl/commands/logs/handlers/syslog.rbs +21 -0
  356. data/sig/pvectl/commands/logs/handlers/task_detail.rbs +21 -0
  357. data/sig/pvectl/commands/logs/handlers/task_logs.rbs +35 -0
  358. data/sig/pvectl/commands/logs/resource_handler.rbs +11 -0
  359. data/sig/pvectl/commands/logs/resource_registry.rbs +8 -0
  360. data/sig/pvectl/commands/migrate_command.rbs +45 -0
  361. data/sig/pvectl/commands/migrate_container.rbs +11 -0
  362. data/sig/pvectl/commands/migrate_vm.rbs +13 -0
  363. data/sig/pvectl/commands/move_disk_command.rbs +43 -0
  364. data/sig/pvectl/commands/move_disk_container.rbs +11 -0
  365. data/sig/pvectl/commands/move_disk_vm.rbs +13 -0
  366. data/sig/pvectl/commands/ping.rbs +39 -0
  367. data/sig/pvectl/commands/pull.rbs +33 -0
  368. data/sig/pvectl/commands/push.rbs +32 -0
  369. data/sig/pvectl/commands/reset.rbs +11 -0
  370. data/sig/pvectl/commands/resource_lifecycle_command.rbs +55 -0
  371. data/sig/pvectl/commands/resource_registry.rbs +19 -0
  372. data/sig/pvectl/commands/restart.rbs +11 -0
  373. data/sig/pvectl/commands/restart_container.rbs +9 -0
  374. data/sig/pvectl/commands/restore_backup.rbs +27 -0
  375. data/sig/pvectl/commands/resume.rbs +11 -0
  376. data/sig/pvectl/commands/rollback_snapshot.rbs +31 -0
  377. data/sig/pvectl/commands/sendkey_vm.rbs +25 -0
  378. data/sig/pvectl/commands/service.rbs +38 -0
  379. data/sig/pvectl/commands/set_container.rbs +13 -0
  380. data/sig/pvectl/commands/set_node.rbs +13 -0
  381. data/sig/pvectl/commands/set_resource_command.rbs +25 -0
  382. data/sig/pvectl/commands/set_vm.rbs +15 -0
  383. data/sig/pvectl/commands/set_volume.rbs +24 -0
  384. data/sig/pvectl/commands/shared_config_parsers.rbs +19 -0
  385. data/sig/pvectl/commands/shared_flags.rbs +10 -0
  386. data/sig/pvectl/commands/shutdown.rbs +11 -0
  387. data/sig/pvectl/commands/shutdown_container.rbs +9 -0
  388. data/sig/pvectl/commands/start.rbs +11 -0
  389. data/sig/pvectl/commands/start_container.rbs +9 -0
  390. data/sig/pvectl/commands/stop.rbs +11 -0
  391. data/sig/pvectl/commands/stop_container.rbs +9 -0
  392. data/sig/pvectl/commands/suspend.rbs +11 -0
  393. data/sig/pvectl/commands/template_command.rbs +21 -0
  394. data/sig/pvectl/commands/template_container.rbs +10 -0
  395. data/sig/pvectl/commands/template_vm.rbs +12 -0
  396. data/sig/pvectl/commands/top/command.rbs +31 -0
  397. data/sig/pvectl/commands/top/handlers/containers.rbs +21 -0
  398. data/sig/pvectl/commands/top/handlers/nodes.rbs +21 -0
  399. data/sig/pvectl/commands/top/handlers/vms.rbs +21 -0
  400. data/sig/pvectl/commands/top/resource_handler.rbs +11 -0
  401. data/sig/pvectl/commands/top/resource_registry.rbs +8 -0
  402. data/sig/pvectl/commands/unlink_disk_vm.rbs +27 -0
  403. data/sig/pvectl/commands/vm_lifecycle_command.rbs +25 -0
  404. data/sig/pvectl/commands/wakeonlan_node.rbs +21 -0
  405. data/sig/pvectl/config/errors.rbs +24 -0
  406. data/sig/pvectl/config/models/cluster.rbs +39 -0
  407. data/sig/pvectl/config/models/context.rbs +23 -0
  408. data/sig/pvectl/config/models/resolved_config.rbs +51 -0
  409. data/sig/pvectl/config/models/user.rbs +31 -0
  410. data/sig/pvectl/config/provider.rbs +40 -0
  411. data/sig/pvectl/config/service.rbs +65 -0
  412. data/sig/pvectl/config/store.rbs +14 -0
  413. data/sig/pvectl/config/wizard.rbs +48 -0
  414. data/sig/pvectl/config_serializer.rbs +121 -0
  415. data/sig/pvectl/connection/retry_handler.rbs +31 -0
  416. data/sig/pvectl/connection.rbs +35 -0
  417. data/sig/pvectl/console/terminal_session.rbs +63 -0
  418. data/sig/pvectl/editor_session.rbs +33 -0
  419. data/sig/pvectl/exit_codes.rbs +19 -0
  420. data/sig/pvectl/formatters/base.rbs +13 -0
  421. data/sig/pvectl/formatters/color_support.rbs +13 -0
  422. data/sig/pvectl/formatters/json.rbs +7 -0
  423. data/sig/pvectl/formatters/output_helper.rbs +9 -0
  424. data/sig/pvectl/formatters/registry.rbs +13 -0
  425. data/sig/pvectl/formatters/table.rbs +25 -0
  426. data/sig/pvectl/formatters/wide.rbs +15 -0
  427. data/sig/pvectl/formatters/yaml.rbs +7 -0
  428. data/sig/pvectl/manifest_serializer.rbs +18 -0
  429. data/sig/pvectl/models/apt_package.rbs +26 -0
  430. data/sig/pvectl/models/backup.rbs +31 -0
  431. data/sig/pvectl/models/base.rbs +11 -0
  432. data/sig/pvectl/models/capability.rbs +16 -0
  433. data/sig/pvectl/models/container.rbs +44 -0
  434. data/sig/pvectl/models/container_operation_result.rbs +9 -0
  435. data/sig/pvectl/models/dns_config.rbs +15 -0
  436. data/sig/pvectl/models/hosts_file.rbs +13 -0
  437. data/sig/pvectl/models/journal_entry.rbs +10 -0
  438. data/sig/pvectl/models/network_interface.rbs +20 -0
  439. data/sig/pvectl/models/node.rbs +47 -0
  440. data/sig/pvectl/models/node_operation_result.rbs +12 -0
  441. data/sig/pvectl/models/operation_result.rbs +21 -0
  442. data/sig/pvectl/models/physical_disk.rbs +35 -0
  443. data/sig/pvectl/models/service.rbs +18 -0
  444. data/sig/pvectl/models/snapshot.rbs +21 -0
  445. data/sig/pvectl/models/snapshot_description.rbs +18 -0
  446. data/sig/pvectl/models/storage.rbs +39 -0
  447. data/sig/pvectl/models/subscription.rbs +24 -0
  448. data/sig/pvectl/models/syslog_entry.rbs +10 -0
  449. data/sig/pvectl/models/task.rbs +22 -0
  450. data/sig/pvectl/models/task_entry.rbs +24 -0
  451. data/sig/pvectl/models/task_log_line.rbs +10 -0
  452. data/sig/pvectl/models/time_config.rbs +12 -0
  453. data/sig/pvectl/models/vm.rbs +32 -0
  454. data/sig/pvectl/models/vm_operation_result.rbs +9 -0
  455. data/sig/pvectl/models/volume.rbs +29 -0
  456. data/sig/pvectl/models/volume_operation_result.rbs +9 -0
  457. data/sig/pvectl/parsers/cloud_init_config.rbs +15 -0
  458. data/sig/pvectl/parsers/disk_config.rbs +19 -0
  459. data/sig/pvectl/parsers/lxc_mount_config.rbs +19 -0
  460. data/sig/pvectl/parsers/lxc_net_config.rbs +19 -0
  461. data/sig/pvectl/parsers/net_config.rbs +19 -0
  462. data/sig/pvectl/parsers/smart_text.rbs +7 -0
  463. data/sig/pvectl/plugin_loader.rbs +25 -0
  464. data/sig/pvectl/presenters/apt_package.rbs +19 -0
  465. data/sig/pvectl/presenters/backup.rbs +25 -0
  466. data/sig/pvectl/presenters/base.rbs +41 -0
  467. data/sig/pvectl/presenters/capability.rbs +19 -0
  468. data/sig/pvectl/presenters/config/context.rbs +17 -0
  469. data/sig/pvectl/presenters/container.rbs +78 -0
  470. data/sig/pvectl/presenters/container_operation_result.rbs +19 -0
  471. data/sig/pvectl/presenters/disk.rbs +31 -0
  472. data/sig/pvectl/presenters/dns_config.rbs +13 -0
  473. data/sig/pvectl/presenters/hosts_file.rbs +13 -0
  474. data/sig/pvectl/presenters/journal_entry.rbs +11 -0
  475. data/sig/pvectl/presenters/node.rbs +118 -0
  476. data/sig/pvectl/presenters/node_operation_result.rbs +11 -0
  477. data/sig/pvectl/presenters/operation_result.rbs +17 -0
  478. data/sig/pvectl/presenters/service.rbs +15 -0
  479. data/sig/pvectl/presenters/snapshot.rbs +35 -0
  480. data/sig/pvectl/presenters/snapshot_operation_result.rbs +27 -0
  481. data/sig/pvectl/presenters/storage.rbs +59 -0
  482. data/sig/pvectl/presenters/subscription.rbs +36 -0
  483. data/sig/pvectl/presenters/syslog_entry.rbs +11 -0
  484. data/sig/pvectl/presenters/task_entry.rbs +21 -0
  485. data/sig/pvectl/presenters/task_log_line.rbs +11 -0
  486. data/sig/pvectl/presenters/template.rbs +15 -0
  487. data/sig/pvectl/presenters/time_config.rbs +19 -0
  488. data/sig/pvectl/presenters/top_container.rbs +17 -0
  489. data/sig/pvectl/presenters/top_node.rbs +17 -0
  490. data/sig/pvectl/presenters/top_presenter.rbs +13 -0
  491. data/sig/pvectl/presenters/top_vm.rbs +17 -0
  492. data/sig/pvectl/presenters/vm.rbs +91 -0
  493. data/sig/pvectl/presenters/vm_operation_result.rbs +19 -0
  494. data/sig/pvectl/presenters/volume.rbs +23 -0
  495. data/sig/pvectl/presenters/volume_operation_result.rbs +11 -0
  496. data/sig/pvectl/repositories/apt.rbs +17 -0
  497. data/sig/pvectl/repositories/backup.rbs +27 -0
  498. data/sig/pvectl/repositories/base.rbs +23 -0
  499. data/sig/pvectl/repositories/capabilities.rbs +20 -0
  500. data/sig/pvectl/repositories/container.rbs +63 -0
  501. data/sig/pvectl/repositories/disk.rbs +17 -0
  502. data/sig/pvectl/repositories/dns.rbs +13 -0
  503. data/sig/pvectl/repositories/hosts.rbs +13 -0
  504. data/sig/pvectl/repositories/journal.rbs +7 -0
  505. data/sig/pvectl/repositories/node.rbs +68 -0
  506. data/sig/pvectl/repositories/service.rbs +27 -0
  507. data/sig/pvectl/repositories/snapshot.rbs +19 -0
  508. data/sig/pvectl/repositories/storage.rbs +37 -0
  509. data/sig/pvectl/repositories/subscription.rbs +17 -0
  510. data/sig/pvectl/repositories/syslog.rbs +7 -0
  511. data/sig/pvectl/repositories/task.rbs +19 -0
  512. data/sig/pvectl/repositories/task_list.rbs +7 -0
  513. data/sig/pvectl/repositories/task_log.rbs +11 -0
  514. data/sig/pvectl/repositories/time_config.rbs +13 -0
  515. data/sig/pvectl/repositories/vm.rbs +85 -0
  516. data/sig/pvectl/repositories/volume.rbs +43 -0
  517. data/sig/pvectl/selectors/base.rbs +37 -0
  518. data/sig/pvectl/selectors/container.rbs +19 -0
  519. data/sig/pvectl/selectors/disk.rbs +13 -0
  520. data/sig/pvectl/selectors/vm.rbs +19 -0
  521. data/sig/pvectl/selectors/volume.rbs +13 -0
  522. data/sig/pvectl/services/backup.rbs +27 -0
  523. data/sig/pvectl/services/clone_container.rbs +35 -0
  524. data/sig/pvectl/services/clone_vm.rbs +35 -0
  525. data/sig/pvectl/services/cloudinit.rbs +19 -0
  526. data/sig/pvectl/services/console.rbs +23 -0
  527. data/sig/pvectl/services/container_lifecycle.rbs +26 -0
  528. data/sig/pvectl/services/create_container.rbs +64 -0
  529. data/sig/pvectl/services/create_vm.rbs +72 -0
  530. data/sig/pvectl/services/edit_container.rbs +17 -0
  531. data/sig/pvectl/services/edit_dns.rbs +23 -0
  532. data/sig/pvectl/services/edit_hosts.rbs +13 -0
  533. data/sig/pvectl/services/edit_node.rbs +21 -0
  534. data/sig/pvectl/services/edit_vm.rbs +17 -0
  535. data/sig/pvectl/services/edit_volume.rbs +18 -0
  536. data/sig/pvectl/services/get/resource_service.rbs +23 -0
  537. data/sig/pvectl/services/move_disk.rbs +21 -0
  538. data/sig/pvectl/services/pull_config.rbs +18 -0
  539. data/sig/pvectl/services/push_config.rbs +37 -0
  540. data/sig/pvectl/services/resize_volume.rbs +47 -0
  541. data/sig/pvectl/services/resource_delete.rbs +27 -0
  542. data/sig/pvectl/services/resource_migration.rbs +29 -0
  543. data/sig/pvectl/services/sendkey.rbs +19 -0
  544. data/sig/pvectl/services/service_lifecycle.rbs +17 -0
  545. data/sig/pvectl/services/set_container.rbs +14 -0
  546. data/sig/pvectl/services/set_node.rbs +23 -0
  547. data/sig/pvectl/services/set_vm.rbs +14 -0
  548. data/sig/pvectl/services/set_volume.rbs +12 -0
  549. data/sig/pvectl/services/snapshot.rbs +35 -0
  550. data/sig/pvectl/services/task_listing.rbs +13 -0
  551. data/sig/pvectl/services/unlink_disk.rbs +17 -0
  552. data/sig/pvectl/services/vm_lifecycle.rbs +26 -0
  553. data/sig/pvectl/services/wakeonlan.rbs +17 -0
  554. data/sig/pvectl/utils/resource_resolver.rbs +17 -0
  555. data/sig/pvectl/wizards/create_container.rbs +21 -0
  556. data/sig/pvectl/wizards/create_vm.rbs +21 -0
  557. data/sig/pvectl.rbs +9 -0
  558. metadata +675 -0
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ module Get
6
+ module Handlers
7
+ # Handler for listing backups.
8
+ #
9
+ # Unlike Snapshots handler, Backups allows listing all backups
10
+ # or filtering by optional VMID.
11
+ #
12
+ # @example Usage
13
+ # handler.list(node: nil, name: nil, args: []) # all backups
14
+ # handler.list(node: nil, name: nil, args: ["100"]) # backups for VM 100
15
+ #
16
+ class Backups
17
+ include ResourceHandler
18
+
19
+ def initialize(service: nil)
20
+ @service = service
21
+ end
22
+
23
+ # Lists backups with optional VMID filter.
24
+ #
25
+ # @param node [String, nil] ignored (backups can span nodes)
26
+ # @param name [String, nil] ignored
27
+ # @param args [Array<String>] optional VMID filter (first arg only)
28
+ # @param storage [String, nil] filter by storage
29
+ # @return [Array<Models::Backup>] collection of backup models
30
+ def list(node: nil, name: nil, args: [], storage: nil, **_options)
31
+ vmid = args.first&.to_i
32
+ vmid = nil if vmid&.zero?
33
+
34
+ service.list(vmid: vmid, storage: storage)
35
+ end
36
+
37
+ # Returns presenter for backups.
38
+ #
39
+ # @return [Presenters::Backup] backup presenter instance
40
+ def presenter
41
+ Pvectl::Presenters::Backup.new
42
+ end
43
+
44
+ private
45
+
46
+ def service
47
+ @service ||= build_service
48
+ end
49
+
50
+ def build_service
51
+ config_service = Pvectl::Config::Service.new
52
+ config_service.load
53
+ connection = Pvectl::Connection.new(config_service.current_config)
54
+
55
+ backup_repo = Pvectl::Repositories::Backup.new(connection)
56
+ resolver = Pvectl::Utils::ResourceResolver.new(connection)
57
+ task_repo = Pvectl::Repositories::Task.new(connection)
58
+
59
+ Pvectl::Services::Backup.new(
60
+ backup_repo: backup_repo,
61
+ resource_resolver: resolver,
62
+ task_repo: task_repo
63
+ )
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ # Register handler with ResourceRegistry
72
+ Pvectl::Commands::Get::ResourceRegistry.register(
73
+ "backups",
74
+ Pvectl::Commands::Get::Handlers::Backups,
75
+ aliases: ["backup"]
76
+ )
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ module Get
6
+ module Handlers
7
+ # Handler for `pvectl get node-capabilities`.
8
+ #
9
+ # Surfaces what features a node supports — primarily the available
10
+ # QEMU CPU models and machine types. When `--node` is provided the
11
+ # query is scoped to that node; otherwise the handler iterates all
12
+ # online nodes and aggregates the results, silently skipping
13
+ # unreachable nodes (matches the pattern used by the time handler).
14
+ #
15
+ # @see Pvectl::Repositories::Capabilities
16
+ # @see Pvectl::Presenters::Capability
17
+ #
18
+ class Capabilities
19
+ include ResourceHandler
20
+
21
+ # @param repository [Repositories::Capabilities, nil] capability repo (DI)
22
+ # @param node_repository [Repositories::Node, nil] node repo (DI)
23
+ def initialize(repository: nil, node_repository: nil)
24
+ @repository = repository
25
+ @node_repository = node_repository
26
+ end
27
+
28
+ # Lists capabilities, optionally scoped to a node.
29
+ #
30
+ # @param node [String, nil] when provided, only that node is queried
31
+ # @param name [String, nil] unused, interface compatibility
32
+ # @param args [Array<String>] unused, interface compatibility
33
+ # @param storage [String, nil] unused, interface compatibility
34
+ # @return [Array<Models::Capability>]
35
+ # @raise [Pvectl::ResourceNotFoundError] if a specific node is requested but missing
36
+ def list(node: nil, name: nil, args: [], storage: nil, **_options)
37
+ return fetch_for(node) if node
38
+
39
+ online_node_names.flat_map do |node_name|
40
+ repository.list(node: node_name)
41
+ rescue StandardError
42
+ []
43
+ end
44
+ end
45
+
46
+ # Returns the capability presenter.
47
+ #
48
+ # @return [Presenters::Capability]
49
+ def presenter
50
+ Pvectl::Presenters::Capability.new
51
+ end
52
+
53
+ private
54
+
55
+ # Fetches capabilities for a specific node, raising when the node
56
+ # itself does not exist in the cluster.
57
+ #
58
+ # @param node_name [String]
59
+ # @return [Array<Models::Capability>]
60
+ # @raise [Pvectl::ResourceNotFoundError]
61
+ def fetch_for(node_name)
62
+ unless node_repository.get(node_name)
63
+ raise Pvectl::ResourceNotFoundError, "Node not found: #{node_name}"
64
+ end
65
+
66
+ repository.list(node: node_name)
67
+ end
68
+
69
+ # Names of online nodes.
70
+ #
71
+ # @return [Array<String>]
72
+ def online_node_names
73
+ node_repository.list.select { |n| n.status == "online" }.map(&:name)
74
+ end
75
+
76
+ # @return [Repositories::Capabilities]
77
+ def repository
78
+ @repository ||= Pvectl::Repositories::Capabilities.new(connection)
79
+ end
80
+
81
+ # @return [Repositories::Node]
82
+ def node_repository
83
+ @node_repository ||= Pvectl::Repositories::Node.new(connection)
84
+ end
85
+
86
+ # Builds API connection from the current config.
87
+ #
88
+ # @return [Pvectl::Connection]
89
+ def connection
90
+ @connection ||= begin
91
+ config_service = Pvectl::Config::Service.new
92
+ config_service.load
93
+ Pvectl::Connection.new(config_service.current_config)
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ # Register handler with ResourceRegistry under the spec name plus aliases.
103
+ Pvectl::Commands::Get::ResourceRegistry.register(
104
+ "node-capabilities",
105
+ Pvectl::Commands::Get::Handlers::Capabilities,
106
+ aliases: ["capabilities", "caps", "node-capability"]
107
+ )
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ module Get
6
+ module Handlers
7
+ # Handler for listing LXC containers.
8
+ #
9
+ # Implements ResourceHandler interface for the "containers" resource type.
10
+ # Uses Repositories::Container for data access and Presenters::Container for formatting.
11
+ #
12
+ # Registered with ResourceRegistry on file load for "containers", "container", "ct", and "cts".
13
+ #
14
+ # @example Using via ResourceRegistry
15
+ # handler = ResourceRegistry.for("containers")
16
+ # containers = handler.list(node: "pve1")
17
+ # presenter = handler.presenter
18
+ #
19
+ # @see Pvectl::Commands::Get::ResourceHandler Handler interface
20
+ # @see Pvectl::Repositories::Container Container repository
21
+ # @see Pvectl::Presenters::Container Container presenter
22
+ #
23
+ class Containers
24
+ include ResourceHandler
25
+
26
+ # CTID validation pattern (100-999999999)
27
+ CTID_PATTERN = /\A[1-9]\d{2,8}\z/
28
+
29
+ # Sort field mappings.
30
+ # Negative values for descending sort (higher values first).
31
+ SORT_FIELDS = {
32
+ "name" => ->(c) { c.name || "" },
33
+ "node" => ->(c) { c.node || "" },
34
+ "cpu" => ->(c) { -(c.cpu || 0) },
35
+ "memory" => ->(c) { -(c.mem || 0) },
36
+ "disk" => ->(c) { -(c.disk || 0) },
37
+ "netin" => ->(c) { -(c.netin || 0) },
38
+ "netout" => ->(c) { -(c.netout || 0) }
39
+ }.freeze
40
+
41
+ # Creates handler with optional repository for dependency injection.
42
+ #
43
+ # @param repository [Repositories::Container, nil] repository (default: create new)
44
+ def initialize(repository: nil)
45
+ @repository = repository
46
+ end
47
+
48
+ # Returns selector class for container filtering.
49
+ #
50
+ # @return [Class] Selectors::Container
51
+ def selector_class
52
+ Pvectl::Selectors::Container
53
+ end
54
+
55
+ # Lists containers with optional filtering and sorting.
56
+ #
57
+ # @param node [String, nil] filter by node name
58
+ # @param name [String, nil] filter by container name
59
+ # @param args [Array<String>] unused, for interface compatibility
60
+ # @param storage [String, nil] unused, for interface compatibility
61
+ # @param sort [String, nil] sort field (name, node, cpu, memory, disk, netin, netout)
62
+ # @return [Array<Models::Container>] collection of Container models
63
+ def list(node: nil, name: nil, args: [], storage: nil, sort: nil, **_options)
64
+ containers = repository.list(node: node)
65
+ containers = containers.select { |c| c.name == name } if name
66
+ containers = apply_sort(containers, sort) if sort
67
+ containers
68
+ end
69
+
70
+ # Returns presenter for containers.
71
+ #
72
+ # @return [Presenters::Container] Container presenter instance
73
+ def presenter
74
+ Pvectl::Presenters::Container.new
75
+ end
76
+
77
+ # Describes a single container with comprehensive details.
78
+ #
79
+ # @param name [String] CTID as string (consistent with handler interface)
80
+ # @param node [String, nil] unused, for API consistency
81
+ # @return [Models::Container] Container model with full details
82
+ # @raise [ArgumentError] if CTID format is invalid
83
+ # @raise [Pvectl::ResourceNotFoundError] if container not found
84
+ def describe(name:, node: nil, args: [], vmid: nil)
85
+ raise ArgumentError, "Invalid CTID: must be positive integer (100-999999999)" unless valid_ctid?(name)
86
+
87
+ ctid = name.to_i
88
+ container = repository.describe(ctid)
89
+ raise Pvectl::ResourceNotFoundError, "Container not found: #{ctid}" if container.nil?
90
+
91
+ container
92
+ end
93
+
94
+ private
95
+
96
+ # Returns repository, creating it if necessary.
97
+ #
98
+ # @return [Repositories::Container] Container repository
99
+ def repository
100
+ @repository ||= build_repository
101
+ end
102
+
103
+ # Builds repository with connection from config.
104
+ #
105
+ # @return [Repositories::Container] configured Container repository
106
+ def build_repository
107
+ config_service = Pvectl::Config::Service.new
108
+ config_service.load
109
+ connection = Pvectl::Connection.new(config_service.current_config)
110
+ Pvectl::Repositories::Container.new(connection)
111
+ end
112
+
113
+ # Applies sorting to containers collection.
114
+ #
115
+ # @param containers [Array<Models::Container>] containers to sort
116
+ # @param sort_field [String] field to sort by
117
+ # @return [Array<Models::Container>] sorted containers
118
+ def apply_sort(containers, sort_field)
119
+ sort_proc = SORT_FIELDS[sort_field.to_s]
120
+ return containers unless sort_proc
121
+
122
+ containers.sort_by(&sort_proc)
123
+ end
124
+
125
+ # Validates CTID format.
126
+ #
127
+ # CTID must be a positive integer between 100 and 999999999.
128
+ # The minimum CTID in Proxmox is 100 (unlike VMID which can be 1).
129
+ #
130
+ # @param ctid [String, nil] CTID to validate
131
+ # @return [Boolean] true if valid
132
+ def valid_ctid?(ctid)
133
+ return false if ctid.nil? || ctid.to_s.empty?
134
+
135
+ ctid.to_s.match?(CTID_PATTERN)
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+
143
+ # Register handler with ResourceRegistry
144
+ Pvectl::Commands::Get::ResourceRegistry.register(
145
+ "containers",
146
+ Pvectl::Commands::Get::Handlers::Containers,
147
+ aliases: ["container", "ct", "cts"]
148
+ )
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ module Get
6
+ module Handlers
7
+ # Handler for listing physical disks on Proxmox nodes.
8
+ #
9
+ # Implements ResourceHandler interface for the "disks" resource type.
10
+ # Uses Repositories::Disk for data access and Presenters::Disk for formatting.
11
+ #
12
+ # @example Using via ResourceRegistry
13
+ # handler = ResourceRegistry.for("disks")
14
+ # disks = handler.list(node: "pve1")
15
+ #
16
+ # @see Pvectl::Commands::Get::ResourceHandler Handler interface
17
+ # @see Pvectl::Repositories::Disk Disk repository
18
+ # @see Pvectl::Presenters::Disk Disk presenter
19
+ #
20
+ class Disks
21
+ include ResourceHandler
22
+
23
+ # Creates handler with optional repository for dependency injection.
24
+ #
25
+ # @param repository [Repositories::Disk, nil] repository (default: create new)
26
+ def initialize(repository: nil)
27
+ @repository = repository
28
+ end
29
+
30
+ # Lists physical disks with optional filtering.
31
+ #
32
+ # @param node [String, nil] filter by node name
33
+ # @param name [String, nil] filter by device path (e.g., "/dev/sda")
34
+ # @param args [Array<String>] unused, for interface compatibility
35
+ # @param storage [String, nil] unused, for interface compatibility
36
+ # @return [Array<Models::PhysicalDisk>] collection of PhysicalDisk models
37
+ def list(node: nil, name: nil, args: [], storage: nil, **_options)
38
+ disks = repository.list(node: node)
39
+ disks = disks.select { |d| d.devpath == name } if name
40
+ disks
41
+ end
42
+
43
+ # Describes a single physical disk with SMART data.
44
+ #
45
+ # Locates the disk by devpath across all nodes (or a specific node),
46
+ # then fetches SMART data and merges it into the model.
47
+ #
48
+ # @param name [String] device path (e.g., "/dev/nvme0n1")
49
+ # @param node [String, nil] optional node filter
50
+ # @param args [Array<String>] unused, for interface compatibility
51
+ # @param vmid [String, nil] unused, for interface compatibility
52
+ # @return [Models::PhysicalDisk] enriched disk model
53
+ # @raise [Pvectl::ResourceNotFoundError] when disk not found
54
+ def describe(name:, node: nil, args: [], vmid: nil)
55
+ disks = repository.list(node: node)
56
+ disk = disks.find { |d| d.devpath == name }
57
+ raise Pvectl::ResourceNotFoundError, "Disk not found: #{name}" unless disk
58
+
59
+ smart_data = repository.smart(disk.node, name)
60
+ disk.merge_smart(smart_data)
61
+ disk
62
+ end
63
+
64
+ # Returns presenter for physical disks.
65
+ #
66
+ # @return [Presenters::Disk] Disk presenter instance
67
+ def presenter
68
+ Pvectl::Presenters::Disk.new
69
+ end
70
+
71
+ # Returns selector class for client-side filtering.
72
+ #
73
+ # @return [Class] Selectors::Disk class
74
+ def selector_class
75
+ Pvectl::Selectors::Disk
76
+ end
77
+
78
+ private
79
+
80
+ # Returns repository, creating it if necessary.
81
+ #
82
+ # @return [Repositories::Disk] Disk repository
83
+ def repository
84
+ @repository ||= build_repository
85
+ end
86
+
87
+ # Builds repository with connection from config.
88
+ #
89
+ # @return [Repositories::Disk] configured Disk repository
90
+ def build_repository
91
+ config_service = Pvectl::Config::Service.new
92
+ config_service.load
93
+ connection = Pvectl::Connection.new(config_service.current_config)
94
+ Pvectl::Repositories::Disk.new(connection)
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ # Register handler with ResourceRegistry
103
+ Pvectl::Commands::Get::ResourceRegistry.register(
104
+ "disks",
105
+ Pvectl::Commands::Get::Handlers::Disks,
106
+ aliases: ["disk"]
107
+ )
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ module Get
6
+ module Handlers
7
+ # Handler for reading per-node DNS resolver settings.
8
+ #
9
+ # Implements ResourceHandler interface for the "dns" resource type.
10
+ # DNS is a singleton resource per node — there is no cluster-wide DNS
11
+ # configuration, so a node name is always required.
12
+ #
13
+ # @example Using via ResourceRegistry
14
+ # handler = ResourceRegistry.for("dns")
15
+ # dns = handler.list(node: "pve1") # => [DnsConfig]
16
+ #
17
+ # @see Pvectl::Repositories::Dns DNS repository
18
+ # @see Pvectl::Presenters::DnsConfig DNS presenter
19
+ #
20
+ class Dns
21
+ include ResourceHandler
22
+
23
+ # Creates handler with optional repository for dependency injection.
24
+ #
25
+ # @param repository [Repositories::Dns, nil] DNS repository
26
+ def initialize(repository: nil)
27
+ @repository = repository
28
+ end
29
+
30
+ # Returns the DNS configuration for the given node, wrapped in an array.
31
+ #
32
+ # @param node [String, nil] node name (REQUIRED — DNS is per-node)
33
+ # @param _options [Hash] unused, for interface compatibility
34
+ # @return [Array<Models::DnsConfig>] single-element array with the DNS config
35
+ # @raise [ArgumentError] when no node is provided
36
+ def list(node: nil, **_options)
37
+ raise ArgumentError, "DNS requires --node NODE to identify which node's settings to read" if node.nil? || node.to_s.empty?
38
+
39
+ [repository.fetch(node)]
40
+ end
41
+
42
+ # Returns presenter for DNS configuration.
43
+ #
44
+ # @return [Presenters::DnsConfig] DNS presenter instance
45
+ def presenter
46
+ Pvectl::Presenters::DnsConfig.new
47
+ end
48
+
49
+ # Describes the DNS configuration for a single node.
50
+ #
51
+ # Accepts either `name` (positional argument from describe command)
52
+ # or `node` (--node flag) as the node identifier.
53
+ #
54
+ # @param name [String, nil] node name (positional)
55
+ # @param node [String, nil] node name (--node flag, fallback)
56
+ # @param _opts [Hash] unused, for interface compatibility
57
+ # @return [Models::DnsConfig] DNS configuration model
58
+ # @raise [ArgumentError] when no node identifier given
59
+ def describe(name:, node: nil, **_opts)
60
+ node_name = name || node
61
+ raise ArgumentError, "Node name required: pvectl describe dns NODE or --node NODE" if node_name.nil? || node_name.to_s.empty?
62
+
63
+ repository.fetch(node_name)
64
+ end
65
+
66
+ private
67
+
68
+ # Returns repository, creating it if necessary.
69
+ #
70
+ # @return [Repositories::Dns] DNS repository
71
+ def repository
72
+ @repository ||= build_repository
73
+ end
74
+
75
+ # Builds repository with connection from config.
76
+ #
77
+ # @return [Repositories::Dns] configured DNS repository
78
+ def build_repository
79
+ config_service = Pvectl::Config::Service.new
80
+ config_service.load
81
+ connection = Pvectl::Connection.new(config_service.current_config)
82
+ Pvectl::Repositories::Dns.new(connection)
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ # Register handler with ResourceRegistry
91
+ Pvectl::Commands::Get::ResourceRegistry.register(
92
+ "dns",
93
+ Pvectl::Commands::Get::Handlers::Dns
94
+ )
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ module Get
6
+ module Handlers
7
+ # Handler for reading per-node /etc/hosts contents.
8
+ #
9
+ # Implements ResourceHandler interface for the "hosts" resource type.
10
+ # /etc/hosts is a singleton resource per node — there is no cluster-wide
11
+ # hosts file, so a node name is always required.
12
+ #
13
+ # @example Using via ResourceRegistry
14
+ # handler = ResourceRegistry.for("hosts")
15
+ # hosts = handler.list(node: "pve1") # => [HostsFile]
16
+ #
17
+ # @see Pvectl::Repositories::Hosts Hosts repository
18
+ # @see Pvectl::Presenters::HostsFile HostsFile presenter
19
+ #
20
+ class Hosts
21
+ include ResourceHandler
22
+
23
+ # Creates handler with optional repository for dependency injection.
24
+ #
25
+ # @param repository [Repositories::Hosts, nil] Hosts repository
26
+ def initialize(repository: nil)
27
+ @repository = repository
28
+ end
29
+
30
+ # Returns the /etc/hosts contents for the given node, wrapped in an array.
31
+ #
32
+ # @param node [String, nil] node name (REQUIRED — hosts is per-node)
33
+ # @param _options [Hash] unused, for interface compatibility
34
+ # @return [Array<Models::HostsFile>] single-element array with the hosts file
35
+ # @raise [ArgumentError] when no node is provided
36
+ def list(node: nil, **_options)
37
+ raise ArgumentError, "hosts requires --node NODE to identify which node's /etc/hosts to read" if node.nil? || node.to_s.empty?
38
+
39
+ [repository.fetch(node)]
40
+ end
41
+
42
+ # Returns presenter for /etc/hosts.
43
+ #
44
+ # @return [Presenters::HostsFile] HostsFile presenter instance
45
+ def presenter
46
+ Pvectl::Presenters::HostsFile.new
47
+ end
48
+
49
+ # Describes the /etc/hosts contents for a single node.
50
+ #
51
+ # Accepts either `name` (positional argument from describe command)
52
+ # or `node` (--node flag) as the node identifier.
53
+ #
54
+ # @param name [String, nil] node name (positional)
55
+ # @param node [String, nil] node name (--node flag, fallback)
56
+ # @param _opts [Hash] unused, for interface compatibility
57
+ # @return [Models::HostsFile] hosts file model
58
+ # @raise [ArgumentError] when no node identifier given
59
+ def describe(name:, node: nil, **_opts)
60
+ node_name = name || node
61
+ raise ArgumentError, "Node name required: pvectl describe hosts NODE or --node NODE" if node_name.nil? || node_name.to_s.empty?
62
+
63
+ repository.fetch(node_name)
64
+ end
65
+
66
+ private
67
+
68
+ # Returns repository, creating it if necessary.
69
+ #
70
+ # @return [Repositories::Hosts] hosts repository
71
+ def repository
72
+ @repository ||= build_repository
73
+ end
74
+
75
+ # Builds repository with connection from config.
76
+ #
77
+ # @return [Repositories::Hosts] configured hosts repository
78
+ def build_repository
79
+ config_service = Pvectl::Config::Service.new
80
+ config_service.load
81
+ connection = Pvectl::Connection.new(config_service.current_config)
82
+ Pvectl::Repositories::Hosts.new(connection)
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ # Register handler with ResourceRegistry
91
+ Pvectl::Commands::Get::ResourceRegistry.register(
92
+ "hosts",
93
+ Pvectl::Commands::Get::Handlers::Hosts
94
+ )