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,99 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Presenters
5
+ # Presenter for APT packages (pending updates and installed versions).
6
+ #
7
+ # Standard columns highlight the upgrade path; wide columns add metadata
8
+ # useful when triaging updates.
9
+ #
10
+ # @example Using with formatter
11
+ # presenter = AptPackage.new
12
+ # formatter = Formatters::Table.new
13
+ # output = formatter.format(packages, presenter)
14
+ #
15
+ # @see Pvectl::Models::AptPackage AptPackage model
16
+ #
17
+ class AptPackage < Base
18
+ # Returns column headers for standard table output.
19
+ #
20
+ # @return [Array<String>] column headers
21
+ def columns
22
+ %w[NODE PACKAGE CURRENT AVAILABLE ORIGIN]
23
+ end
24
+
25
+ # Returns additional column headers for wide output.
26
+ #
27
+ # @return [Array<String>] extra column headers
28
+ def extra_columns
29
+ %w[ARCH SECTION PRIORITY DESCRIPTION]
30
+ end
31
+
32
+ # Converts AptPackage model to table row values.
33
+ #
34
+ # @param model [Models::AptPackage] package model
35
+ # @param context [Hash] optional context
36
+ # @return [Array<String>] row values matching columns order
37
+ def to_row(model, **_context)
38
+ [
39
+ model.node || "-",
40
+ model.package || "-",
41
+ model.old_version || "-",
42
+ model.version || "-",
43
+ model.origin || "-"
44
+ ]
45
+ end
46
+
47
+ # Returns additional values for wide output.
48
+ #
49
+ # @param model [Models::AptPackage] package model
50
+ # @param context [Hash] optional context
51
+ # @return [Array<String>] extra values matching extra_columns order
52
+ def extra_values(model, **_context)
53
+ [
54
+ model.arch || "-",
55
+ model.section || "-",
56
+ model.priority || "-",
57
+ truncate(model.description, 60)
58
+ ]
59
+ end
60
+
61
+ # Converts AptPackage model to hash for JSON/YAML output.
62
+ #
63
+ # @param model [Models::AptPackage] package model
64
+ # @return [Hash] hash representation with string keys
65
+ def to_hash(model)
66
+ {
67
+ "node" => model.node,
68
+ "package" => model.package,
69
+ "title" => model.title,
70
+ "current_version" => model.old_version,
71
+ "available_version" => model.version,
72
+ "origin" => model.origin,
73
+ "arch" => model.arch,
74
+ "section" => model.section,
75
+ "priority" => model.priority,
76
+ "description" => model.description,
77
+ "notify_status" => model.notify_status,
78
+ "current_state" => model.current_state,
79
+ "manager_version" => model.manager_version,
80
+ "running_kernel" => model.running_kernel
81
+ }
82
+ end
83
+
84
+ private
85
+
86
+ # Truncates text to fit in a column.
87
+ #
88
+ # @param text [String, nil] text to truncate
89
+ # @param length [Integer] maximum length
90
+ # @return [String] truncated text or "-"
91
+ def truncate(text, length)
92
+ return "-" if text.nil? || text.empty?
93
+ return text if text.length <= length
94
+
95
+ "#{text[0, length - 1]}…"
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Presenters
5
+ # Presenter for Backup models.
6
+ #
7
+ # Formats backups for table, wide, JSON, and YAML output.
8
+ # Standard columns: VMID, TYPE, CREATED, SIZE, STORAGE, PROTECTED
9
+ # Wide columns add: FORMAT, NOTES, VOLID
10
+ #
11
+ # @example Using with formatter
12
+ # presenter = Backup.new
13
+ # formatter = Formatters::Table.new
14
+ # output = formatter.format(backups, presenter)
15
+ #
16
+ # @see Pvectl::Models::Backup Backup model
17
+ # @see Pvectl::Formatters::Table Table formatter
18
+ #
19
+ class Backup < Base
20
+ # Returns column headers for standard table output.
21
+ #
22
+ # @return [Array<String>] column headers
23
+ def columns
24
+ %w[VMID TYPE CREATED SIZE STORAGE PROTECTED]
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[FORMAT NOTES VOLID]
32
+ end
33
+
34
+ # Converts Backup model to table row values.
35
+ #
36
+ # @param model [Models::Backup] Backup model
37
+ # @param context [Hash] optional context
38
+ # @return [Array] row values matching columns order
39
+ def to_row(model, **_context)
40
+ [
41
+ model.vmid,
42
+ format_type(model.resource_type),
43
+ format_time(model.created_at),
44
+ model.human_size,
45
+ model.storage,
46
+ format_protected(model.protected?)
47
+ ]
48
+ end
49
+
50
+ # Returns additional values for wide output.
51
+ #
52
+ # @param model [Models::Backup] Backup model
53
+ # @param context [Hash] optional context
54
+ # @return [Array] extra values matching extra_columns order
55
+ def extra_values(model, **_context)
56
+ [
57
+ model.format,
58
+ truncate(model.notes, 30),
59
+ model.volid
60
+ ]
61
+ end
62
+
63
+ # Converts Backup model to hash for JSON/YAML output.
64
+ #
65
+ # @param model [Models::Backup] Backup model
66
+ # @return [Hash] hash representation with string keys
67
+ def to_hash(model)
68
+ {
69
+ "vmid" => model.vmid,
70
+ "type" => format_type(model.resource_type),
71
+ "volid" => model.volid,
72
+ "storage" => model.storage,
73
+ "node" => model.node,
74
+ "size" => model.size,
75
+ "size_human" => model.human_size,
76
+ "created_at" => model.created_at&.iso8601,
77
+ "format" => model.format,
78
+ "notes" => model.notes,
79
+ "protected" => model.protected?
80
+ }
81
+ end
82
+
83
+ private
84
+
85
+ # Formats resource type for display.
86
+ #
87
+ # @param resource_type [Symbol, nil] :qemu or :lxc
88
+ # @return [String] formatted type
89
+ def format_type(resource_type)
90
+ case resource_type
91
+ when :qemu then "qemu"
92
+ when :lxc then "lxc"
93
+ else "-"
94
+ end
95
+ end
96
+
97
+ # Formats time for display.
98
+ #
99
+ # @param time [Time, nil] time to format
100
+ # @return [String] formatted time or "-" if nil
101
+ def format_time(time)
102
+ return "-" if time.nil?
103
+
104
+ time.strftime("%Y-%m-%d %H:%M:%S")
105
+ end
106
+
107
+ # Formats protected status for display.
108
+ #
109
+ # @param protected [Boolean] protection status
110
+ # @return [String] "yes" or "no"
111
+ def format_protected(protected_status)
112
+ protected_status ? "yes" : "no"
113
+ end
114
+
115
+ # Truncates text to specified length.
116
+ #
117
+ # @param text [String, nil] text to truncate
118
+ # @param max_length [Integer] maximum length
119
+ # @return [String, nil] truncated text or nil
120
+ def truncate(text, max_length)
121
+ return nil if text.nil?
122
+ return text if text.length <= max_length
123
+
124
+ "#{text[0, max_length - 3]}..."
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,283 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Presenters
5
+ # Abstract base class for resource presenters.
6
+ #
7
+ # Presenters define how models are displayed in different formats.
8
+ # Each resource type (VM, Container, Node, etc.) has its own presenter.
9
+ #
10
+ # @abstract Subclass and implement {#columns}, {#to_row}, and {#to_hash}.
11
+ #
12
+ # @example Implementing a resource presenter
13
+ # class VmPresenter < Base
14
+ # def columns
15
+ # ["NAME", "STATUS", "NODE"]
16
+ # end
17
+ #
18
+ # def extra_columns
19
+ # ["MEMORY", "CPU"]
20
+ # end
21
+ #
22
+ # def to_row(model, **context)
23
+ # [model.name, model.status, model.node]
24
+ # end
25
+ #
26
+ # def extra_values(model, **context)
27
+ # [model.memory, model.cpu]
28
+ # end
29
+ #
30
+ # def to_hash(model)
31
+ # { "name" => model.name, "status" => model.status, "node" => model.node }
32
+ # end
33
+ # end
34
+ #
35
+ # @see Pvectl::Formatters::OutputHelper for using presenters with formatters
36
+ #
37
+ class Base
38
+ # Returns column headers for table format.
39
+ #
40
+ # @return [Array<String>] column names (uppercase, e.g., ["NAME", "STATUS"])
41
+ # @raise [NotImplementedError] if not implemented by subclass
42
+ def columns
43
+ raise NotImplementedError, "#{self.class}#columns must be implemented"
44
+ end
45
+
46
+ # Returns extended column headers for wide format.
47
+ # By default, appends extra_columns to columns.
48
+ #
49
+ # @return [Array<String>] column names (normal + extra)
50
+ def wide_columns
51
+ columns + extra_columns
52
+ end
53
+
54
+ # Returns additional columns for wide format.
55
+ # Override in subclass to add extra columns.
56
+ #
57
+ # @return [Array<String>] extra column names (empty by default)
58
+ def extra_columns
59
+ []
60
+ end
61
+
62
+ # Converts model to table row values.
63
+ #
64
+ # @param model [Object] domain model object
65
+ # @param context [Hash] optional context (e.g., current_context: "prod")
66
+ # @return [Array<String, nil>] row values matching columns order
67
+ # @raise [NotImplementedError] if not implemented by subclass
68
+ def to_row(model, **context)
69
+ raise NotImplementedError, "#{self.class}#to_row must be implemented"
70
+ end
71
+
72
+ # Converts model to wide table row values.
73
+ # By default, appends extra_values to to_row.
74
+ #
75
+ # @param model [Object] domain model object
76
+ # @param context [Hash] optional context
77
+ # @return [Array<String, nil>] row values (normal + extra)
78
+ def to_wide_row(model, **context)
79
+ to_row(model, **context) + extra_values(model, **context)
80
+ end
81
+
82
+ # Returns additional values for wide format.
83
+ # Override in subclass to add extra values.
84
+ #
85
+ # @param model [Object] domain model object
86
+ # @param context [Hash] optional context
87
+ # @return [Array<String, nil>] extra values (empty by default)
88
+ def extra_values(model, **context)
89
+ []
90
+ end
91
+
92
+ # Converts model to hash for JSON/YAML format.
93
+ #
94
+ # @param model [Object] domain model object
95
+ # @return [Hash] hash representation with string keys
96
+ # @raise [NotImplementedError] if not implemented by subclass
97
+ def to_hash(model)
98
+ raise NotImplementedError, "#{self.class}#to_hash must be implemented"
99
+ end
100
+
101
+ # Converts model to description format (kubectl-style vertical layout).
102
+ # By default, delegates to to_hash. Override for custom describe output.
103
+ #
104
+ # @param model [Object] domain model object
105
+ # @return [Hash] hash representation (keys become labels)
106
+ def to_description(model)
107
+ to_hash(model)
108
+ end
109
+
110
+ # Returns uptime in human-readable format.
111
+ # Delegates to resource.uptime. Override in subclasses with custom logic.
112
+ #
113
+ # @return [String] formatted uptime (e.g., "15d 3h") or "-"
114
+ def uptime_human
115
+ uptime = resource.uptime
116
+ return "-" if uptime.nil? || uptime.zero?
117
+
118
+ days = uptime / 86_400
119
+ hours = (uptime % 86_400) / 3600
120
+ minutes = (uptime % 3600) / 60
121
+
122
+ if days.positive?
123
+ "#{days}d #{hours}h"
124
+ elsif hours.positive?
125
+ "#{hours}h #{minutes}m"
126
+ else
127
+ "#{minutes}m"
128
+ end
129
+ end
130
+
131
+ # Returns tags as array.
132
+ #
133
+ # @return [Array<String>] array of tags, or empty array if no tags
134
+ def tags_array
135
+ tags = resource.tags
136
+ return [] if tags.nil? || tags.empty?
137
+
138
+ tags.split(";").map(&:strip)
139
+ end
140
+
141
+ # Returns tags as comma-separated string.
142
+ #
143
+ # @return [String] formatted tags (e.g., "prod, web") or "-" if no tags
144
+ def tags_display
145
+ arr = tags_array
146
+ arr.empty? ? "-" : arr.join(", ")
147
+ end
148
+
149
+ # Returns template display string.
150
+ #
151
+ # @return [String] "yes" if template, "-" otherwise
152
+ def template_display
153
+ resource.template? ? "yes" : "-"
154
+ end
155
+
156
+ private
157
+
158
+ # Returns the current resource model.
159
+ # Must be implemented by subclasses.
160
+ #
161
+ # @return [Object] current model
162
+ # @raise [NotImplementedError] if not implemented
163
+ def resource
164
+ raise NotImplementedError, "#{self.class}#resource must be implemented"
165
+ end
166
+
167
+ # Formats task history for describe output.
168
+ #
169
+ # @param tasks [Array<Models::TaskEntry>, nil] recent tasks
170
+ # @return [Array<Hash>, String] table data or "No task history"
171
+ def format_task_history(tasks)
172
+ return "No task history" if tasks.nil? || tasks.empty?
173
+
174
+ tasks.map do |task|
175
+ start = task.starttime ? Time.at(task.starttime).strftime("%Y-%m-%d %H:%M:%S") : "-"
176
+ dur = task.duration ? "#{task.duration}s" : "-"
177
+ {
178
+ "TYPE" => task.type || "-",
179
+ "STATUS" => task.exitstatus || task.status || "-",
180
+ "DATE" => start,
181
+ "DURATION" => dur,
182
+ "USER" => task.user || "-"
183
+ }
184
+ end
185
+ end
186
+
187
+ # Formats Firewall section from dedicated API data.
188
+ #
189
+ # Shows firewall options, rules, aliases, and IP sets
190
+ # from the /firewall/ API endpoints. Shared by VM and CT presenters.
191
+ #
192
+ # @param firewall_data [Hash, nil] firewall data with :options, :rules, :aliases, :ipset
193
+ # @return [Hash, String] firewall info or "-" if no data
194
+ def format_firewall(firewall_data)
195
+ return "-" if firewall_data.nil? || firewall_data.empty?
196
+
197
+ options = firewall_data[:options]
198
+ options = {} unless options.is_a?(Hash)
199
+ aliases = firewall_data[:aliases]
200
+ aliases = [] unless aliases.is_a?(Array)
201
+ ipset = firewall_data[:ipset]
202
+ ipset = [] unless ipset.is_a?(Array)
203
+
204
+ result = {
205
+ "Enable" => options[:enable] == 1 ? "Yes" : "No",
206
+ "Input Policy" => (options[:policy_in] || "DROP").to_s,
207
+ "Output Policy" => (options[:policy_out] || "ACCEPT").to_s
208
+ }
209
+
210
+ # Optional options
211
+ result["DHCP"] = options[:dhcp] == 1 ? "Yes" : "No" if options.key?(:dhcp)
212
+ result["MAC Filter"] = options[:macfilter] == 1 ? "Yes" : "No" if options.key?(:macfilter)
213
+ result["IP Filter"] = options[:ipfilter] == 1 ? "Yes" : "No" if options.key?(:ipfilter)
214
+ result["NDP"] = options[:ndp] == 1 ? "Yes" : "No" if options.key?(:ndp)
215
+ result["Router Advertisement"] = options[:radv] == 1 ? "Yes" : "No" if options.key?(:radv)
216
+ result["Log Level In"] = options[:log_level_in].to_s if options[:log_level_in] && options[:log_level_in] != "nolog"
217
+ result["Log Level Out"] = options[:log_level_out].to_s if options[:log_level_out] && options[:log_level_out] != "nolog"
218
+
219
+ # Aliases table
220
+ if aliases.any?
221
+ result["Aliases"] = aliases.map do |a|
222
+ { "NAME" => a[:name] || "-", "CIDR" => a[:cidr] || "-", "COMMENT" => a[:comment] || "-" }
223
+ end
224
+ end
225
+
226
+ # IP Sets table
227
+ if ipset.any?
228
+ result["IP Sets"] = ipset.map do |s|
229
+ { "NAME" => s[:name] || "-", "COMMENT" => s[:comment] || "-" }
230
+ end
231
+ end
232
+
233
+ result
234
+ end
235
+
236
+ # Formats Firewall Rules section as a standalone table.
237
+ #
238
+ # Renders firewall rules with the columns: ENABLED, TYPE, ACTION,
239
+ # PROTO, SOURCE, DEST, COMMENT. Used as a top-level describe section
240
+ # for VMs and containers. Empty or missing rules render as "-".
241
+ #
242
+ # @param firewall_data [Hash, nil] firewall data with :rules key
243
+ # @return [Array<Hash>, String] rules table or "-" when empty
244
+ def format_firewall_rules(firewall_data)
245
+ return "-" if firewall_data.nil? || firewall_data.empty?
246
+
247
+ rules = firewall_data[:rules]
248
+ rules = [] unless rules.is_a?(Array)
249
+ return "-" if rules.empty?
250
+
251
+ rules.sort_by { |r| r[:pos].to_i }.map do |rule|
252
+ {
253
+ "ENABLED" => rule[:enable] == 1 ? "yes" : "no",
254
+ "TYPE" => rule[:type]&.to_s&.upcase || "-",
255
+ "ACTION" => rule[:action] || "-",
256
+ "PROTO" => rule[:proto] || "-",
257
+ "SOURCE" => (rule[:source].nil? || rule[:source].to_s.empty?) ? "-" : rule[:source],
258
+ "DEST" => (rule[:dest].nil? || rule[:dest].to_s.empty?) ? "-" : rule[:dest],
259
+ "COMMENT" => (rule[:comment].nil? || rule[:comment].to_s.empty?) ? "-" : rule[:comment]
260
+ }
261
+ end
262
+ end
263
+
264
+ # Formats bytes to human readable string.
265
+ #
266
+ # @param bytes [Integer, nil] bytes
267
+ # @return [String] formatted size
268
+ def format_bytes(bytes)
269
+ return "-" if bytes.nil? || bytes.zero?
270
+
271
+ if bytes >= 1024 * 1024 * 1024
272
+ "#{(bytes.to_f / 1024 / 1024 / 1024).round(1)} GiB"
273
+ elsif bytes >= 1024 * 1024
274
+ "#{(bytes.to_f / 1024 / 1024).round(1)} MiB"
275
+ elsif bytes >= 1024
276
+ "#{(bytes.to_f / 1024).round(1)} KiB"
277
+ else
278
+ "#{bytes} B"
279
+ end
280
+ end
281
+ end
282
+ end
283
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Presenters
5
+ # Presenter for node capabilities (QEMU CPU models, machine types).
6
+ #
7
+ # Each Capability becomes one row regardless of kind. The DETAILS
8
+ # column adapts to the kind: CPU rows show vendor (and the "custom"
9
+ # marker when applicable), machine rows show the underlying machine
10
+ # family (q35/i440fx).
11
+ #
12
+ # @example Using with formatter
13
+ # presenter = Capability.new
14
+ # formatter = Formatters::Table.new
15
+ # output = formatter.format(capabilities, presenter)
16
+ #
17
+ # @see Pvectl::Models::Capability
18
+ #
19
+ class Capability < Base
20
+ # Returns column headers for table output.
21
+ #
22
+ # @return [Array<String>] column headers
23
+ def columns
24
+ ["NODE", "KIND", "NAME", "DETAILS"]
25
+ end
26
+
27
+ # Returns extra columns for wide output (machine version, custom flag).
28
+ #
29
+ # @return [Array<String>] extra columns
30
+ def extra_columns
31
+ ["VERSION"]
32
+ end
33
+
34
+ # Converts capability to a row.
35
+ #
36
+ # @param model [Models::Capability]
37
+ # @param _context [Hash] unused
38
+ # @return [Array<String>]
39
+ def to_row(model, **_context)
40
+ [
41
+ model.node_name || "-",
42
+ model.kind.to_s,
43
+ model.name || "-",
44
+ details(model)
45
+ ]
46
+ end
47
+
48
+ # Returns extra values for wide output.
49
+ #
50
+ # @param model [Models::Capability]
51
+ # @param _context [Hash] unused
52
+ # @return [Array<String>]
53
+ def extra_values(model, **_context)
54
+ [model.version || "-"]
55
+ end
56
+
57
+ # Converts capability to a hash for JSON/YAML output.
58
+ #
59
+ # Only the fields relevant to the kind are included; unset fields
60
+ # are omitted to keep the output compact and readable.
61
+ #
62
+ # @param model [Models::Capability]
63
+ # @return [Hash{String => Object}]
64
+ def to_hash(model)
65
+ base = {
66
+ "node" => model.node_name,
67
+ "kind" => model.kind&.to_s,
68
+ "name" => model.name
69
+ }
70
+
71
+ case model.kind
72
+ when :cpu
73
+ base["vendor"] = model.vendor if model.vendor
74
+ base["custom"] = model.custom
75
+ when :machine
76
+ base["machine_type"] = model.machine_type if model.machine_type
77
+ base["version"] = model.version if model.version
78
+ base["changes"] = model.changes if model.changes
79
+ end
80
+
81
+ base
82
+ end
83
+
84
+ private
85
+
86
+ # Returns the DETAILS column string.
87
+ #
88
+ # @param model [Models::Capability]
89
+ # @return [String]
90
+ def details(model)
91
+ case model.kind
92
+ when :cpu
93
+ parts = [model.vendor].compact
94
+ parts << "custom" if model.custom
95
+ parts.empty? ? "-" : parts.join(" ")
96
+ when :machine
97
+ model.machine_type || "-"
98
+ else
99
+ "-"
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Presenters
5
+ module Config
6
+ # Presenter for formatting context list output.
7
+ #
8
+ # Context presenter provides column definitions and row formatting
9
+ # for displaying contexts in table, wide table, JSON, and YAML formats.
10
+ # Inherits from Base to support unified output formatting.
11
+ #
12
+ # @example Using with OutputHelper
13
+ # presenter = Context.new
14
+ # OutputHelper.print(
15
+ # data: contexts,
16
+ # presenter: presenter,
17
+ # format: "table",
18
+ # current_context: "production"
19
+ # )
20
+ #
21
+ # @example Wide format includes DEFAULT-NODE column
22
+ # pvectl config get-contexts -o wide
23
+ # # CURRENT NAME CLUSTER USER DEFAULT-NODE
24
+ # # * production prod admin@pam pve1
25
+ #
26
+ class Context < Pvectl::Presenters::Base
27
+ # Returns the column headers for table output.
28
+ #
29
+ # @return [Array<String>] column names
30
+ def columns
31
+ ["CURRENT", "NAME", "CLUSTER", "USER"]
32
+ end
33
+
34
+ # Returns additional columns for wide format.
35
+ #
36
+ # @return [Array<String>] extra column names
37
+ def extra_columns
38
+ ["DEFAULT-NODE"]
39
+ end
40
+
41
+ # Converts a context to a table row.
42
+ #
43
+ # @param context [Config::Models::Context] context to format
44
+ # @param current_context [String, nil] name of the current context
45
+ # @param context_kwargs [Hash] additional context (ignored)
46
+ # @return [Array<String>] row values
47
+ def to_row(context, current_context: nil, **context_kwargs)
48
+ [
49
+ context.name == current_context ? "*" : "",
50
+ context.name,
51
+ context.cluster_ref,
52
+ context.user_ref
53
+ ]
54
+ end
55
+
56
+ # Returns additional values for wide format.
57
+ #
58
+ # @param context [Config::Models::Context] context to format
59
+ # @param context_kwargs [Hash] additional context (ignored)
60
+ # @return [Array<String, nil>] extra values
61
+ def extra_values(context, **context_kwargs)
62
+ [context.default_node]
63
+ end
64
+
65
+ # Converts a context to a hash for JSON/YAML output.
66
+ #
67
+ # @param context [Config::Models::Context] context to format
68
+ # @return [Hash] hash representation
69
+ def to_hash(context)
70
+ {
71
+ "name" => context.name,
72
+ "cluster" => context.cluster_ref,
73
+ "user" => context.user_ref,
74
+ "default_node" => context.default_node
75
+ }
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end