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,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Presenters
5
+ # Presenter for node operation results (set/edit).
6
+ #
7
+ # Formats NodeOperationResult models for table/JSON/YAML output.
8
+ #
9
+ # @example Using with formatter
10
+ # presenter = NodeOperationResult.new
11
+ # formatter = Formatters::Table.new
12
+ # output = formatter.format(results, presenter)
13
+ #
14
+ class NodeOperationResult < OperationResult
15
+ # Returns column headers for standard table output.
16
+ #
17
+ # @return [Array<String>] column headers
18
+ def columns
19
+ %w[NODE OPERATION STATUS MESSAGE]
20
+ end
21
+
22
+ # Converts result to table row values.
23
+ #
24
+ # @param model [Models::NodeOperationResult] result model
25
+ # @param context [Hash] optional context
26
+ # @return [Array<String>] row values
27
+ def to_row(model, **_context)
28
+ [
29
+ model.node_model&.name || "-",
30
+ model.operation&.to_s || "-",
31
+ status_display(model),
32
+ model.message
33
+ ]
34
+ end
35
+
36
+ # Converts result to hash for JSON/YAML output.
37
+ #
38
+ # @param model [Models::NodeOperationResult] result model
39
+ # @return [Hash] hash representation
40
+ def to_hash(model)
41
+ {
42
+ "node" => model.node_model&.name,
43
+ "operation" => model.operation&.to_s,
44
+ "status" => model.status_text,
45
+ "message" => model.message
46
+ }
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Presenters
5
+ # Base presenter for lifecycle operation results.
6
+ #
7
+ # Provides shared formatting helpers (status colors, task UPID, duration)
8
+ # for subclasses like VmOperationResult and ContainerOperationResult.
9
+ #
10
+ # @abstract Subclass and implement columns, to_row, extra_values, to_hash.
11
+ #
12
+ class OperationResult < Base
13
+ include Formatters::ColorSupport
14
+
15
+ protected
16
+
17
+ # Returns colored status display.
18
+ #
19
+ # @param model [Models::OperationResult] result model
20
+ # @return [String] colored status
21
+ def status_display(model)
22
+ case model.status_text
23
+ when "Success" then colorize(model.status_text, :green)
24
+ when "Failed" then colorize(model.status_text, :red)
25
+ when "Pending" then colorize(model.status_text, :yellow)
26
+ when "Partial" then colorize(model.status_text, :bright_yellow)
27
+ else model.status_text
28
+ end
29
+ end
30
+
31
+ # Returns task UPID or dash.
32
+ #
33
+ # @param model [Models::OperationResult] result model
34
+ # @return [String] UPID or "-"
35
+ def task_upid(model)
36
+ model.task_upid || model.task&.upid || "-"
37
+ end
38
+
39
+ # Returns formatted duration.
40
+ #
41
+ # @param model [Models::OperationResult] result model
42
+ # @return [String] duration or "-"
43
+ def duration_display(model)
44
+ duration = model.task&.duration
45
+ return "-" unless duration
46
+
47
+ "#{duration.to_f.round(1)}s"
48
+ end
49
+
50
+ # Colorizes text using Pastel.
51
+ #
52
+ # @param text [String] text to colorize
53
+ # @param color [Symbol] color name (:green, :red, :yellow)
54
+ # @return [String] colored text
55
+ def colorize(text, color)
56
+ pastel = Formatters::ColorSupport.pastel(explicit_flag: nil)
57
+ pastel.public_send(color, text)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Presenters
5
+ # Presenter for systemd services on Proxmox nodes.
6
+ #
7
+ # Defines column layout and formatting for table output of node services.
8
+ # Standard columns show node, name, state, active, enabled, description.
9
+ # Wide adds the systemd unit identifier.
10
+ #
11
+ # @example Using with formatter
12
+ # presenter = Service.new
13
+ # formatter = Formatters::Table.new
14
+ # output = formatter.format(services, presenter)
15
+ #
16
+ # @see Pvectl::Models::Service Service model
17
+ # @see Pvectl::Formatters::Table Table formatter
18
+ #
19
+ class Service < Base
20
+ # Returns column headers for standard table output.
21
+ #
22
+ # @return [Array<String>] column headers
23
+ def columns
24
+ %w[NODE NAME STATE ACTIVE ENABLED DESCRIPTION]
25
+ end
26
+
27
+ # Returns additional column headers for wide output.
28
+ #
29
+ # @return [Array<String>] extra column headers
30
+ def extra_columns
31
+ %w[UNIT]
32
+ end
33
+
34
+ # Converts a Service model to table row values.
35
+ #
36
+ # @param model [Models::Service] Service model
37
+ # @param context [Hash] optional context
38
+ # @return [Array<String>] row values matching columns order
39
+ def to_row(model, **_context)
40
+ [
41
+ model.node || "-",
42
+ model.display_name || "-",
43
+ model.state || "-",
44
+ model.active_state || "-",
45
+ model.unit_state || "-",
46
+ model.desc || "-"
47
+ ]
48
+ end
49
+
50
+ # Returns additional values for wide output.
51
+ #
52
+ # @param model [Models::Service] Service model
53
+ # @param context [Hash] optional context
54
+ # @return [Array<String>] extra values matching extra_columns order
55
+ def extra_values(model, **_context)
56
+ [model.service || "-"]
57
+ end
58
+
59
+ # Converts a Service model to hash for JSON/YAML output.
60
+ #
61
+ # @param model [Models::Service] Service model
62
+ # @return [Hash{String => String?}] hash representation
63
+ def to_hash(model)
64
+ {
65
+ "node" => model.node,
66
+ "service" => model.service,
67
+ "name" => model.name,
68
+ "state" => model.state,
69
+ "active_state" => model.active_state,
70
+ "unit_state" => model.unit_state,
71
+ "desc" => model.desc
72
+ }
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,239 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Presenters
5
+ # Presenter for VM/container snapshots.
6
+ #
7
+ # Defines column layout and formatting for snapshot table output.
8
+ # Supports both list (get) and describe output modes.
9
+ #
10
+ # Standard columns: VMID, NAME, CREATED, DESCRIPTION
11
+ # Wide columns add: TYPE, VMSTATE, PARENT
12
+ #
13
+ # @example Using with formatter
14
+ # presenter = Snapshot.new
15
+ # formatter = Formatters::Table.new
16
+ # output = formatter.format(snapshots, presenter)
17
+ #
18
+ # @see Pvectl::Models::Snapshot Snapshot model
19
+ # @see Pvectl::Models::SnapshotDescription SnapshotDescription model
20
+ # @see Pvectl::Formatters::Table Table formatter
21
+ #
22
+ class Snapshot < Base
23
+ # Returns column headers for standard table output.
24
+ #
25
+ # @return [Array<String>] column headers
26
+ def columns
27
+ %w[VMID NAME CREATED DESCRIPTION]
28
+ end
29
+
30
+ # Returns additional column headers for wide output.
31
+ #
32
+ # @return [Array<String>] extra column headers
33
+ def extra_columns
34
+ %w[TYPE VMSTATE PARENT]
35
+ end
36
+
37
+ # Converts Snapshot model to table row values.
38
+ #
39
+ # @param model [Models::Snapshot] Snapshot model
40
+ # @param context [Hash] optional context
41
+ # @return [Array<String>] row values matching columns order
42
+ def to_row(model, **_context)
43
+ [
44
+ model.vmid.to_s,
45
+ model.name,
46
+ format_time(model.created_at),
47
+ model.description || "-"
48
+ ]
49
+ end
50
+
51
+ # Returns additional values for wide output.
52
+ #
53
+ # @param model [Models::Snapshot] Snapshot model
54
+ # @param context [Hash] optional context
55
+ # @return [Array<String>] extra values matching extra_columns order
56
+ def extra_values(model, **_context)
57
+ [
58
+ model.resource_type&.to_s || "-",
59
+ model.has_vmstate? ? "yes" : "no",
60
+ model.parent || "-"
61
+ ]
62
+ end
63
+
64
+ # Converts model to hash for JSON/YAML output.
65
+ #
66
+ # Handles both Models::Snapshot (for list) and
67
+ # Models::SnapshotDescription (for describe).
68
+ #
69
+ # @param model [Models::Snapshot, Models::SnapshotDescription] model
70
+ # @return [Hash, Array<Hash>] hash representation with string keys
71
+ def to_hash(model)
72
+ return snapshot_to_hash(model) unless model.is_a?(Models::SnapshotDescription)
73
+
74
+ if model.single?
75
+ entry = model.entries.first
76
+ snapshot_to_hash(entry.snapshot).merge(
77
+ "snapshot_tree" => build_tree_data(entry)
78
+ )
79
+ else
80
+ model.entries.map do |entry|
81
+ snapshot_to_hash(entry.snapshot).merge(
82
+ "snapshot_tree" => build_tree_data(entry)
83
+ )
84
+ end
85
+ end
86
+ end
87
+
88
+ # Returns describe output for SnapshotDescription or plain Snapshot.
89
+ #
90
+ # @param model [Models::SnapshotDescription, Models::Snapshot] model
91
+ # @return [Hash] description hash for formatter
92
+ def to_description(model)
93
+ return snapshot_to_hash(model) unless model.is_a?(Models::SnapshotDescription)
94
+
95
+ if model.single?
96
+ build_single_description(model.entries.first)
97
+ else
98
+ build_multi_description(model.entries)
99
+ end
100
+ end
101
+
102
+ private
103
+
104
+ # Converts a single Snapshot model to hash.
105
+ #
106
+ # @param model [Models::Snapshot] Snapshot model
107
+ # @return [Hash] hash representation
108
+ def snapshot_to_hash(model)
109
+ {
110
+ "vmid" => model.vmid,
111
+ "name" => model.name,
112
+ "node" => model.node,
113
+ "type" => model.resource_type&.to_s,
114
+ "description" => model.description,
115
+ "vmstate" => model.has_vmstate?,
116
+ "parent" => model.parent,
117
+ "created" => format_time(model.created_at)
118
+ }
119
+ end
120
+
121
+ # Builds describe hash for a single VM entry.
122
+ #
123
+ # @param entry [Models::SnapshotDescription::Entry] entry
124
+ # @return [Hash] description hash
125
+ def build_single_description(entry)
126
+ snap = entry.snapshot
127
+ {
128
+ "Name" => snap.name,
129
+ "VMID" => snap.vmid,
130
+ "Node" => snap.node,
131
+ "Type" => snap.resource_type&.to_s,
132
+ "Created" => format_time(snap.created_at),
133
+ "Description" => snap.description || "-",
134
+ "VM State" => snap.has_vmstate? ? "Yes" : "No",
135
+ "Parent" => snap.parent || "-",
136
+ "Snapshot Tree" => build_tree_string(entry)
137
+ }
138
+ end
139
+
140
+ # Builds describe hash for multiple VM entries.
141
+ #
142
+ # @param entries [Array<Models::SnapshotDescription::Entry>] entries
143
+ # @return [Hash] nested hash with section per VM
144
+ def build_multi_description(entries)
145
+ result = {}
146
+ entries.each do |entry|
147
+ snap = entry.snapshot
148
+ label = snap.vm? ? "VM" : "CT"
149
+ header = "#{label} #{snap.vmid} (#{snap.node})"
150
+ result[header] = build_single_description(entry)
151
+ end
152
+ result
153
+ end
154
+
155
+ # Builds tree string for display in table format.
156
+ #
157
+ # @param entry [Models::SnapshotDescription::Entry] entry with siblings
158
+ # @return [String] multi-line tree string
159
+ def build_tree_string(entry)
160
+ children_map = build_children_map(entry.siblings)
161
+ roots = entry.siblings.select { |s| s.parent.nil? }.map(&:name)
162
+ all_roots = roots + ["(current)"]
163
+
164
+ lines = []
165
+ all_roots.each_with_index do |root, idx|
166
+ last = idx == all_roots.length - 1
167
+ if root == "(current)"
168
+ lines << "#{last ? "\u2514\u2500" : "\u251c\u2500"} (current)"
169
+ else
170
+ render_tree_node(root, children_map, entry.snapshot.name, "", last, lines)
171
+ end
172
+ end
173
+
174
+ lines.join("\n")
175
+ end
176
+
177
+ # Recursively renders a tree node.
178
+ #
179
+ # @param name [String] snapshot name
180
+ # @param children_map [Hash] parent -> children mapping
181
+ # @param target [String] target snapshot name to mark
182
+ # @param prefix [String] indentation prefix
183
+ # @param last [Boolean] whether this is the last sibling
184
+ # @param lines [Array<String>] accumulator for output lines
185
+ # @return [void]
186
+ def render_tree_node(name, children_map, target, prefix, last, lines)
187
+ connector = last ? "\u2514\u2500" : "\u251c\u2500"
188
+ marker = name == target ? " \u25c0" : ""
189
+ lines << "#{prefix}#{connector} #{name}#{marker}"
190
+
191
+ children = children_map[name] || []
192
+ children.each_with_index do |child, idx|
193
+ child_prefix = prefix + (last ? " " : "\u2502 ")
194
+ child_last = idx == children.length - 1
195
+ render_tree_node(child, children_map, target, child_prefix, child_last, lines)
196
+ end
197
+ end
198
+
199
+ # Builds parent -> children mapping from siblings.
200
+ #
201
+ # @param siblings [Array<Models::Snapshot>] all snapshots for a VM
202
+ # @return [Hash<String, Array<String>>] parent name -> child names
203
+ def build_children_map(siblings)
204
+ map = Hash.new { |h, k| h[k] = [] }
205
+ siblings.each do |snap|
206
+ map[snap.parent] << snap.name if snap.parent
207
+ end
208
+ map
209
+ end
210
+
211
+ # Builds structured tree data for JSON/YAML output.
212
+ #
213
+ # @param entry [Models::SnapshotDescription::Entry] entry with siblings
214
+ # @return [Array<Hash>] tree nodes with children and current_target flag
215
+ def build_tree_data(entry)
216
+ children_map = build_children_map(entry.siblings)
217
+ entry.siblings.map do |snap|
218
+ node = {
219
+ "name" => snap.name,
220
+ "parent" => snap.parent,
221
+ "children" => children_map[snap.name] || []
222
+ }
223
+ node["current_target"] = true if snap.name == entry.snapshot.name
224
+ node
225
+ end
226
+ end
227
+
228
+ # Formats time for display.
229
+ #
230
+ # @param time [Time, nil] time to format
231
+ # @return [String] formatted time or "-" if nil
232
+ def format_time(time)
233
+ return "-" if time.nil?
234
+
235
+ time.strftime("%Y-%m-%d %H:%M:%S")
236
+ end
237
+ end
238
+ end
239
+ end
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Presenters
5
+ # Presenter for snapshot operation results.
6
+ #
7
+ # Formats OperationResult models from snapshot operations for table/JSON/YAML output.
8
+ # Unlike OperationResult presenter, this handles resource hash instead of VM model.
9
+ #
10
+ # @example Using with formatter
11
+ # presenter = SnapshotOperationResult.new
12
+ # formatter = Formatters::Table.new
13
+ # output = formatter.format(results, presenter)
14
+ #
15
+ class SnapshotOperationResult < Base
16
+ include Formatters::ColorSupport
17
+
18
+ # Returns column headers for standard table output.
19
+ #
20
+ # @return [Array<String>] column headers
21
+ def columns
22
+ %w[VMID NAME TYPE NODE STATUS MESSAGE]
23
+ end
24
+
25
+ # Returns additional columns for wide output.
26
+ #
27
+ # @return [Array<String>] extra column headers
28
+ def extra_columns
29
+ %w[TASK DURATION]
30
+ end
31
+
32
+ # Converts result to table row values.
33
+ #
34
+ # @param model [Models::OperationResult] result model
35
+ # @param context [Hash] optional context
36
+ # @return [Array<String>] row values
37
+ def to_row(model, **_context)
38
+ resource = model.resource || {}
39
+ [
40
+ resource[:vmid].to_s,
41
+ resource[:name] || "-",
42
+ resource[:type]&.to_s || "-",
43
+ resource[:node] || "-",
44
+ status_display(model),
45
+ model.message
46
+ ]
47
+ end
48
+
49
+ # Returns additional values for wide output.
50
+ #
51
+ # @param model [Models::OperationResult] result model
52
+ # @param context [Hash] optional context
53
+ # @return [Array<String>] extra values
54
+ def extra_values(model, **_context)
55
+ [
56
+ task_upid(model),
57
+ duration_display(model)
58
+ ]
59
+ end
60
+
61
+ # Converts result to hash for JSON/YAML output.
62
+ #
63
+ # @param model [Models::OperationResult] result model
64
+ # @return [Hash] hash representation
65
+ def to_hash(model)
66
+ resource = model.resource || {}
67
+ {
68
+ "vmid" => resource[:vmid],
69
+ "name" => resource[:name],
70
+ "type" => resource[:type]&.to_s,
71
+ "node" => resource[:node],
72
+ "operation" => model.operation&.to_s,
73
+ "status" => model.status_text,
74
+ "message" => model.message,
75
+ "task_upid" => model.task_upid || model.task&.upid
76
+ }
77
+ end
78
+
79
+ private
80
+
81
+ # Returns colored status display.
82
+ #
83
+ # @param model [Models::OperationResult] result model
84
+ # @return [String] colored status
85
+ def status_display(model)
86
+ case model.status_text
87
+ when "Success" then colorize(model.status_text, :green)
88
+ when "Failed" then colorize(model.status_text, :red)
89
+ when "Pending" then colorize(model.status_text, :yellow)
90
+ when "Partial" then colorize(model.status_text, :bright_yellow)
91
+ else model.status_text
92
+ end
93
+ end
94
+
95
+ # Returns task UPID or dash.
96
+ #
97
+ # @param model [Models::OperationResult] result model
98
+ # @return [String] UPID or "-"
99
+ def task_upid(model)
100
+ model.task_upid || model.task&.upid || "-"
101
+ end
102
+
103
+ # Returns formatted duration.
104
+ #
105
+ # @param model [Models::OperationResult] result model
106
+ # @return [String] duration or "-"
107
+ def duration_display(model)
108
+ duration = model.task&.duration
109
+ return "-" unless duration
110
+
111
+ "#{duration.to_f.round(1)}s"
112
+ end
113
+
114
+ # Colorizes text using Pastel.
115
+ #
116
+ # @param text [String] text to colorize
117
+ # @param color [Symbol] color name (:green, :red, :yellow)
118
+ # @return [String] colored text
119
+ def colorize(text, color)
120
+ pastel = Formatters::ColorSupport.pastel(explicit_flag: nil)
121
+ pastel.public_send(color, text)
122
+ end
123
+ end
124
+ end
125
+ end