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,175 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ module Get
6
+ module Handlers
7
+ # Handler for listing templates (both VM and container).
8
+ #
9
+ # Queries both VM and Container repositories, filters by template? == true,
10
+ # and merges into a single list. Supports --type flag for filtering by
11
+ # resource type (vm/ct/qemu/lxc).
12
+ #
13
+ # @example Using via ResourceRegistry
14
+ # handler = ResourceRegistry.for("templates")
15
+ # templates = handler.list(type_filter: "vm")
16
+ #
17
+ # @see Pvectl::Repositories::Vm VM repository
18
+ # @see Pvectl::Repositories::Container Container repository
19
+ # @see Pvectl::Presenters::Template Template presenter
20
+ #
21
+ class Templates
22
+ include ResourceHandler
23
+
24
+ # Type filter mapping — normalizes user input to API type values.
25
+ TYPE_MAP = {
26
+ "vm" => "qemu",
27
+ "qemu" => "qemu",
28
+ "ct" => "lxc",
29
+ "container" => "lxc",
30
+ "lxc" => "lxc"
31
+ }.freeze
32
+
33
+ # Sort field mappings for template listing.
34
+ SORT_FIELDS = {
35
+ "name" => ->(t) { t.name || "" },
36
+ "node" => ->(t) { t.node || "" },
37
+ "type" => ->(t) { t.type || "" },
38
+ "disk" => ->(t) { -(t.maxdisk || 0) }
39
+ }.freeze
40
+
41
+ # Creates handler with optional repositories for dependency injection.
42
+ #
43
+ # @param vm_repository [Repositories::Vm, nil] VM repository
44
+ # @param container_repository [Repositories::Container, nil] Container repository
45
+ def initialize(vm_repository: nil, container_repository: nil)
46
+ @vm_repository = vm_repository
47
+ @container_repository = container_repository
48
+ end
49
+
50
+ # Lists templates with optional filtering.
51
+ #
52
+ # @param node [String, nil] filter by node name
53
+ # @param type_filter [String, nil] filter by type (vm, ct, qemu, lxc)
54
+ # @param sort [String, nil] sort field
55
+ # @param name [String, nil] unused, interface compatibility
56
+ # @raise [ArgumentError] if type_filter is not a recognized type
57
+ # @return [Array<Models::Vm, Models::Container>] template models
58
+ def list(node: nil, name: nil, type_filter: nil, sort: nil, **_options)
59
+ validate_type_filter!(type_filter)
60
+
61
+ templates = []
62
+
63
+ unless skip_vms?(type_filter)
64
+ vms = vm_repository.list(node: node)
65
+ templates.concat(vms.select(&:template?))
66
+ end
67
+
68
+ unless skip_containers?(type_filter)
69
+ containers = container_repository.list(node: node)
70
+ templates.concat(containers.select(&:template?))
71
+ end
72
+
73
+ templates = apply_sort(templates, sort) if sort
74
+ templates
75
+ end
76
+
77
+ # Returns presenter for templates.
78
+ #
79
+ # @return [Presenters::Template] template presenter
80
+ def presenter
81
+ Pvectl::Presenters::Template.new
82
+ end
83
+
84
+ private
85
+
86
+ # Validates type_filter value against known types.
87
+ #
88
+ # @param type_filter [String, nil] type filter value
89
+ # @raise [ArgumentError] if type_filter is not a recognized type
90
+ # @return [void]
91
+ def validate_type_filter!(type_filter)
92
+ return if type_filter.nil?
93
+ return if TYPE_MAP.key?(type_filter)
94
+
95
+ valid_types = TYPE_MAP.keys.join(", ")
96
+ raise ArgumentError, "Unknown type: #{type_filter}. Valid types: #{valid_types}"
97
+ end
98
+
99
+ # Returns VM repository, creating it if necessary.
100
+ #
101
+ # @return [Repositories::Vm]
102
+ def vm_repository
103
+ @vm_repository ||= build_vm_repository
104
+ end
105
+
106
+ # Returns Container repository, creating it if necessary.
107
+ #
108
+ # @return [Repositories::Container]
109
+ def container_repository
110
+ @container_repository ||= build_container_repository
111
+ end
112
+
113
+ # Builds VM repository with connection from config.
114
+ #
115
+ # @return [Repositories::Vm]
116
+ def build_vm_repository
117
+ config_service = Pvectl::Config::Service.new
118
+ config_service.load
119
+ connection = Pvectl::Connection.new(config_service.current_config)
120
+ Pvectl::Repositories::Vm.new(connection)
121
+ end
122
+
123
+ # Builds Container repository with connection from config.
124
+ #
125
+ # @return [Repositories::Container]
126
+ def build_container_repository
127
+ config_service = Pvectl::Config::Service.new
128
+ config_service.load
129
+ connection = Pvectl::Connection.new(config_service.current_config)
130
+ Pvectl::Repositories::Container.new(connection)
131
+ end
132
+
133
+ # Checks if VMs should be skipped based on type filter.
134
+ #
135
+ # @param type_filter [String, nil] type filter value
136
+ # @return [Boolean]
137
+ def skip_vms?(type_filter)
138
+ return false if type_filter.nil?
139
+
140
+ TYPE_MAP[type_filter] == "lxc"
141
+ end
142
+
143
+ # Checks if containers should be skipped based on type filter.
144
+ #
145
+ # @param type_filter [String, nil] type filter value
146
+ # @return [Boolean]
147
+ def skip_containers?(type_filter)
148
+ return false if type_filter.nil?
149
+
150
+ TYPE_MAP[type_filter] == "qemu"
151
+ end
152
+
153
+ # Applies sorting to templates collection.
154
+ #
155
+ # @param templates [Array] templates to sort
156
+ # @param sort_field [String] field to sort by
157
+ # @return [Array] sorted templates
158
+ def apply_sort(templates, sort_field)
159
+ sort_proc = SORT_FIELDS[sort_field.to_s]
160
+ return templates unless sort_proc
161
+
162
+ templates.sort_by(&sort_proc)
163
+ end
164
+ end
165
+ end
166
+ end
167
+ end
168
+ end
169
+
170
+ # Register handler with ResourceRegistry
171
+ Pvectl::Commands::Get::ResourceRegistry.register(
172
+ "templates",
173
+ Pvectl::Commands::Get::Handlers::Templates,
174
+ aliases: ["template"]
175
+ )
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ module Get
6
+ module Handlers
7
+ # Handler for listing node time and timezone settings.
8
+ #
9
+ # Implements ResourceHandler interface for the "time" resource type.
10
+ # When `--node` is supplied, returns the time config for that single node.
11
+ # Otherwise, iterates over all online nodes and aggregates their time configs.
12
+ # Unreachable nodes (those that raise during fetch) are silently skipped so
13
+ # one bad node does not abort the whole listing.
14
+ #
15
+ # @example Using via ResourceRegistry
16
+ # handler = ResourceRegistry.for("time")
17
+ # configs = handler.list(node: "pve1")
18
+ #
19
+ # @see Pvectl::Commands::Get::ResourceHandler Handler interface
20
+ # @see Pvectl::Repositories::TimeConfig Time repository
21
+ # @see Pvectl::Presenters::TimeConfig Time presenter
22
+ #
23
+ class Time
24
+ include ResourceHandler
25
+
26
+ # Creates handler with optional repositories for dependency injection.
27
+ #
28
+ # @param repository [Repositories::TimeConfig, nil] time repository
29
+ # @param node_repository [Repositories::Node, nil] node repository
30
+ def initialize(repository: nil, node_repository: nil)
31
+ @repository = repository
32
+ @node_repository = node_repository
33
+ end
34
+
35
+ # Lists time/timezone configs.
36
+ #
37
+ # @param node [String, nil] when given, only that node is queried;
38
+ # otherwise iterates all online nodes
39
+ # @param name [String, nil] unused, for interface compatibility
40
+ # @param args [Array<String>] unused, for interface compatibility
41
+ # @param storage [String, nil] unused, for interface compatibility
42
+ # @return [Array<Models::TimeConfig>] one entry per node queried
43
+ # @raise [Pvectl::ResourceNotFoundError] if a specific node was requested but does not exist
44
+ def list(node: nil, name: nil, args: [], storage: nil, **_options)
45
+ return [fetch_for(node)] if node
46
+
47
+ online_node_names.filter_map do |node_name|
48
+ begin
49
+ repository.fetch(node_name)
50
+ rescue StandardError
51
+ # Skip unreachable nodes - one bad node should not abort the listing.
52
+ nil
53
+ end
54
+ end
55
+ end
56
+
57
+ # Returns presenter for time configs.
58
+ #
59
+ # @return [Presenters::TimeConfig]
60
+ def presenter
61
+ Pvectl::Presenters::TimeConfig.new
62
+ end
63
+
64
+ private
65
+
66
+ # Fetches the time config for a specific node, raising ResourceNotFoundError
67
+ # if the node itself does not exist in the cluster.
68
+ #
69
+ # @param node_name [String] node name
70
+ # @return [Models::TimeConfig]
71
+ # @raise [Pvectl::ResourceNotFoundError] if the node does not exist
72
+ def fetch_for(node_name)
73
+ unless node_repository.get(node_name)
74
+ raise Pvectl::ResourceNotFoundError, "Node not found: #{node_name}"
75
+ end
76
+
77
+ repository.fetch(node_name)
78
+ end
79
+
80
+ # Names of online nodes (offline nodes are skipped because querying
81
+ # them is guaranteed to fail).
82
+ #
83
+ # @return [Array<String>] node names
84
+ def online_node_names
85
+ node_repository.list.select { |n| n.status == "online" }.map(&:name)
86
+ end
87
+
88
+ # @return [Repositories::TimeConfig] time repository, lazily built
89
+ def repository
90
+ @repository ||= Pvectl::Repositories::TimeConfig.new(connection)
91
+ end
92
+
93
+ # @return [Repositories::Node] node repository, lazily built
94
+ def node_repository
95
+ @node_repository ||= Pvectl::Repositories::Node.new(connection)
96
+ end
97
+
98
+ # Builds API connection from current config.
99
+ #
100
+ # @return [Pvectl::Connection]
101
+ def connection
102
+ @connection ||= begin
103
+ config_service = Pvectl::Config::Service.new
104
+ config_service.load
105
+ Pvectl::Connection.new(config_service.current_config)
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
113
+
114
+ # Register handler with ResourceRegistry
115
+ Pvectl::Commands::Get::ResourceRegistry.register(
116
+ "time",
117
+ Pvectl::Commands::Get::Handlers::Time
118
+ )
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ module Get
6
+ module Handlers
7
+ # Handler for listing QEMU virtual machines.
8
+ #
9
+ # Implements ResourceHandler interface for the "vms" resource type.
10
+ # Uses Repositories::Vm for data access and Presenters::Vm for formatting.
11
+ #
12
+ # Registered with ResourceRegistry on file load for both "vms" and "vm".
13
+ #
14
+ # @example Using via ResourceRegistry
15
+ # handler = ResourceRegistry.for("vms")
16
+ # vms = handler.list(node: "pve1")
17
+ # presenter = handler.presenter
18
+ #
19
+ # @see Pvectl::Commands::Get::ResourceHandler Handler interface
20
+ # @see Pvectl::Repositories::Vm VM repository
21
+ # @see Pvectl::Presenters::Vm VM presenter
22
+ #
23
+ class Vms
24
+ include ResourceHandler
25
+
26
+ # VMID validation pattern (1-999999999)
27
+ VMID_PATTERN = /\A[1-9]\d{0,8}\z/
28
+
29
+ # Sort field mappings.
30
+ # Negative values for descending sort (higher values first).
31
+ SORT_FIELDS = {
32
+ "name" => ->(v) { v.name || "" },
33
+ "node" => ->(v) { v.node || "" },
34
+ "cpu" => ->(v) { -(v.cpu || 0) },
35
+ "memory" => ->(v) { -(v.mem || 0) },
36
+ "disk" => ->(v) { -(v.disk || 0) },
37
+ "netin" => ->(v) { -(v.netin || 0) },
38
+ "netout" => ->(v) { -(v.netout || 0) }
39
+ }.freeze
40
+
41
+ # Creates handler with optional repository for dependency injection.
42
+ #
43
+ # @param repository [Repositories::Vm, nil] repository (default: create new)
44
+ def initialize(repository: nil)
45
+ @repository = repository
46
+ end
47
+
48
+ # Returns selector class for VM filtering.
49
+ #
50
+ # @return [Class] Selectors::Vm
51
+ def selector_class
52
+ Pvectl::Selectors::Vm
53
+ end
54
+
55
+ # Lists VMs with optional filtering and sorting.
56
+ #
57
+ # @param node [String, nil] filter by node name
58
+ # @param name [String, nil] filter by VM 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::Vm>] collection of VM models
63
+ def list(node: nil, name: nil, args: [], storage: nil, sort: nil, **_options)
64
+ vms = repository.list(node: node)
65
+ vms = vms.select { |vm| vm.name == name } if name
66
+ vms = apply_sort(vms, sort) if sort
67
+ vms
68
+ end
69
+
70
+ # Returns presenter for VMs.
71
+ #
72
+ # @return [Presenters::Vm] VM presenter instance
73
+ def presenter
74
+ Pvectl::Presenters::Vm.new
75
+ end
76
+
77
+ # Describes a single VM with comprehensive details.
78
+ #
79
+ # @param name [String] VMID as string (consistent with handler interface)
80
+ # @param node [String, nil] unused, for API consistency
81
+ # @return [Models::Vm] VM model with full details
82
+ # @raise [ArgumentError] if VMID format is invalid
83
+ # @raise [Pvectl::ResourceNotFoundError] if VM not found
84
+ def describe(name:, node: nil, args: [], vmid: nil)
85
+ raise ArgumentError, "Invalid VMID: must be positive integer (1-999999999)" unless valid_vmid?(name)
86
+
87
+ vmid = name.to_i
88
+ vm = repository.describe(vmid)
89
+ raise Pvectl::ResourceNotFoundError, "VM not found: #{vmid}" if vm.nil?
90
+
91
+ vm
92
+ end
93
+
94
+ private
95
+
96
+ # Returns repository, creating it if necessary.
97
+ #
98
+ # @return [Repositories::Vm] VM repository
99
+ def repository
100
+ @repository ||= build_repository
101
+ end
102
+
103
+ # Builds repository with connection from config.
104
+ #
105
+ # @return [Repositories::Vm] configured VM 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::Vm.new(connection)
111
+ end
112
+
113
+ # Applies sorting to VMs collection.
114
+ #
115
+ # @param vms [Array<Models::Vm>] VMs to sort
116
+ # @param sort_field [String] field to sort by
117
+ # @return [Array<Models::Vm>] sorted VMs
118
+ def apply_sort(vms, sort_field)
119
+ sort_proc = SORT_FIELDS[sort_field.to_s]
120
+ return vms unless sort_proc
121
+
122
+ vms.sort_by(&sort_proc)
123
+ end
124
+
125
+ # Validates VMID format.
126
+ #
127
+ # @param vmid [String, nil] VMID to validate
128
+ # @return [Boolean] true if valid
129
+ def valid_vmid?(vmid)
130
+ return false if vmid.nil? || vmid.to_s.empty?
131
+
132
+ vmid.to_s.match?(VMID_PATTERN)
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ # Register handler with ResourceRegistry
141
+ Pvectl::Commands::Get::ResourceRegistry.register(
142
+ "vms",
143
+ Pvectl::Commands::Get::Handlers::Vms,
144
+ aliases: ["vm"]
145
+ )
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ module Get
6
+ module Handlers
7
+ # Handler for listing and describing virtual disk volumes.
8
+ #
9
+ # Implements ResourceHandler interface for the "volumes" resource type.
10
+ # Supports two listing modes:
11
+ # - Config mode: list volumes from VM/CT config by resource type and IDs
12
+ # - Storage mode: list volumes from a specific storage
13
+ #
14
+ # Uses Repositories::Volume for data access, Presenters::Volume for
15
+ # formatting, and Selectors::Volume for client-side filtering.
16
+ #
17
+ # @example List VM volumes via ResourceRegistry
18
+ # handler = ResourceRegistry.for("volumes")
19
+ # volumes = handler.list(args: ["vm", "100"], node: "pve1")
20
+ #
21
+ # @example List storage volumes
22
+ # handler = ResourceRegistry.for("volumes")
23
+ # volumes = handler.list(storage: "local-lvm")
24
+ #
25
+ # @example Describe a specific volume
26
+ # handler = ResourceRegistry.for("volumes")
27
+ # volume = handler.describe(name: "vm", args: ["100", "scsi0"])
28
+ #
29
+ # @see Pvectl::Commands::Get::ResourceHandler Handler interface
30
+ # @see Pvectl::Repositories::Volume Volume repository
31
+ # @see Pvectl::Presenters::Volume Volume presenter
32
+ #
33
+ class Volume
34
+ include ResourceHandler
35
+
36
+ # Creates handler with optional repository for dependency injection.
37
+ #
38
+ # @param repository [Repositories::Volume, nil] repository (default: create new)
39
+ def initialize(repository: nil)
40
+ @repository = repository
41
+ end
42
+
43
+ # Lists virtual disk volumes with two modes of operation.
44
+ #
45
+ # Config mode: requires resource type and at least one ID in args.
46
+ # args = ["vm", "100", "101"] lists volumes from VMs 100 and 101.
47
+ #
48
+ # Storage mode: requires storage parameter.
49
+ # storage = "local-lvm" lists all volumes on that storage.
50
+ #
51
+ # @param args [Array<String>] resource type and IDs (config mode)
52
+ # @param storage [String, nil] storage name (storage mode)
53
+ # @param node [String, nil] filter by node name
54
+ # @param _options [Hash] unused, for interface compatibility
55
+ # @return [Array<Models::Volume>] collection of Volume models
56
+ def list(args: [], storage: nil, node: nil, **_options)
57
+ if storage
58
+ repository.list_from_storage(storage: storage, node: node)
59
+ elsif args.length >= 2
60
+ resource_type = args[0]
61
+ ids = args[1..].map(&:to_i)
62
+ repository.list_from_config(resource_type: resource_type, ids: ids, node: node)
63
+ else
64
+ $stderr.puts "Usage: pvectl get volume <vm|ct> <ID...> [--node NODE]"
65
+ $stderr.puts " pvectl get volume --storage <STORAGE> [--node NODE]"
66
+ []
67
+ end
68
+ end
69
+
70
+ # Describes a single virtual disk volume.
71
+ #
72
+ # Locates a specific disk by resource type, ID, and disk name.
73
+ #
74
+ # @param name [String] resource type ("vm" or "ct")
75
+ # @param args [Array<String>] [id, disk_name] pair
76
+ # @param node [String, nil] optional node filter
77
+ # @param _options [Hash] unused, for interface compatibility
78
+ # @return [Models::Volume] found Volume model
79
+ # @raise [Pvectl::ResourceNotFoundError] when volume not found
80
+ def describe(name:, args: [], node: nil, **_options)
81
+ resource_type = name
82
+ id = args[0]&.to_i
83
+ disk_name = args[1]
84
+
85
+ volume = repository.find(resource_type: resource_type, id: id, disk_name: disk_name, node: node)
86
+ raise Pvectl::ResourceNotFoundError, "Volume '#{disk_name}' not found on #{resource_type} #{id}" unless volume
87
+
88
+ volume
89
+ end
90
+
91
+ # Returns presenter for virtual disk volumes.
92
+ #
93
+ # @return [Presenters::Volume] Volume presenter instance
94
+ def presenter
95
+ Pvectl::Presenters::Volume.new
96
+ end
97
+
98
+ # Returns selector class for client-side filtering.
99
+ #
100
+ # @return [Class] Selectors::Volume class
101
+ def selector_class
102
+ Pvectl::Selectors::Volume
103
+ end
104
+
105
+ private
106
+
107
+ # Returns repository, creating it if necessary.
108
+ #
109
+ # @return [Repositories::Volume] Volume repository
110
+ def repository
111
+ @repository ||= build_repository
112
+ end
113
+
114
+ # Builds repository with connection from config.
115
+ #
116
+ # @return [Repositories::Volume] configured Volume repository
117
+ def build_repository
118
+ config_service = Pvectl::Config::Service.new
119
+ config_service.load
120
+ connection = Pvectl::Connection.new(config_service.current_config)
121
+ Pvectl::Repositories::Volume.new(connection)
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ # Register handler with ResourceRegistry
130
+ Pvectl::Commands::Get::ResourceRegistry.register(
131
+ "volumes",
132
+ Pvectl::Commands::Get::Handlers::Volume,
133
+ aliases: ["volume", "vol"]
134
+ )
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ module Get
6
+ # Interface module for resource handlers.
7
+ #
8
+ # Each resource type (nodes, vms, containers, storage) implements
9
+ # this interface to provide listing capabilities.
10
+ #
11
+ # Minimal interface with two methods:
12
+ # - #list - fetches and returns model objects
13
+ # - #presenter - returns presenter for formatting
14
+ #
15
+ # @abstract Include in handler class and implement required methods.
16
+ #
17
+ # @example Implementing a handler
18
+ # class NodesHandler
19
+ # include ResourceHandler
20
+ #
21
+ # def list(node: nil, name: nil)
22
+ # # Fetch and return array of Node models
23
+ # repository.list.select { |n| name.nil? || n.name == name }
24
+ # end
25
+ #
26
+ # def presenter
27
+ # Presenters::Node.new
28
+ # end
29
+ # end
30
+ #
31
+ module ResourceHandler
32
+ # Lists resources, optionally filtered by node and name.
33
+ #
34
+ # @param node [String, nil] filter by node name (for VMs/containers)
35
+ # @param name [String, nil] filter by resource name
36
+ # @param _options [Hash] additional options passed through from CLI (e.g., limit, since, type_filter)
37
+ # @return [Array<Object>] collection of model objects
38
+ # @raise [NotImplementedError] if not implemented by including class
39
+ def list(node: nil, name: nil, **_options)
40
+ raise NotImplementedError, "#{self.class}#list must be implemented"
41
+ end
42
+
43
+ # Returns the presenter for this resource type.
44
+ #
45
+ # @return [Presenters::Base] presenter instance
46
+ # @raise [NotImplementedError] if not implemented by including class
47
+ def presenter
48
+ raise NotImplementedError, "#{self.class}#presenter must be implemented"
49
+ end
50
+
51
+ # Returns the selector class for client-side filtering.
52
+ #
53
+ # Handlers that support selector-based filtering (e.g., -l status=running)
54
+ # should override this to return their selector class.
55
+ #
56
+ # @return [Class, nil] selector class (e.g., Selectors::Vm) or nil if not supported
57
+ def selector_class
58
+ nil
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Commands
5
+ module Get
6
+ # Registry for Get command resource handlers.
7
+ #
8
+ # Inherits all registration and lookup logic from Commands::ResourceRegistry.
9
+ # Each handler registers itself at load time.
10
+ #
11
+ # @example Looking up a handler
12
+ # handler = ResourceRegistry.for("nodes")
13
+ # handler.list(node: "pve1") if handler
14
+ #
15
+ class ResourceRegistry < Commands::ResourceRegistry; end
16
+ end
17
+ end
18
+ end