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,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Presenters
5
+ # Presenter for VM lifecycle operation results.
6
+ #
7
+ # Formats VmOperationResult models for table/JSON/YAML output.
8
+ #
9
+ # @example Using with formatter
10
+ # presenter = VmOperationResult.new
11
+ # formatter = Formatters::Table.new
12
+ # output = formatter.format(results, presenter)
13
+ #
14
+ class VmOperationResult < OperationResult
15
+ # Returns column headers for standard table output.
16
+ #
17
+ # @return [Array<String>] column headers
18
+ def columns
19
+ %w[VMID NAME NODE STATUS MESSAGE]
20
+ end
21
+
22
+ # Returns additional columns for wide output.
23
+ #
24
+ # @return [Array<String>] extra column headers
25
+ def extra_columns
26
+ %w[TASK DURATION]
27
+ end
28
+
29
+ # Converts result to table row values.
30
+ #
31
+ # For clone operations, displays the new (cloned) VM data.
32
+ # For all other operations, displays the source VM data.
33
+ #
34
+ # @param model [Models::VmOperationResult] result model
35
+ # @param context [Hash] optional context
36
+ # @return [Array<String>] row values
37
+ def to_row(model, **_context)
38
+ if model.operation == :clone && model.resource
39
+ [
40
+ model.resource[:new_vmid].to_s,
41
+ model.resource[:name] || "VM-#{model.resource[:new_vmid]}",
42
+ model.resource[:node] || model.vm&.node,
43
+ status_display(model),
44
+ model.message
45
+ ]
46
+ else
47
+ [
48
+ model.vm.vmid.to_s,
49
+ display_name(model.vm),
50
+ model.vm.node,
51
+ status_display(model),
52
+ model.message
53
+ ]
54
+ end
55
+ end
56
+
57
+ # Returns additional values for wide output.
58
+ #
59
+ # @param model [Models::VmOperationResult] result model
60
+ # @param context [Hash] optional context
61
+ # @return [Array<String>] extra values
62
+ def extra_values(model, **_context)
63
+ [
64
+ task_upid(model),
65
+ duration_display(model)
66
+ ]
67
+ end
68
+
69
+ # Converts result to hash for JSON/YAML output.
70
+ #
71
+ # For clone operations, displays the new (cloned) VM data.
72
+ # For all other operations, displays the source VM data.
73
+ #
74
+ # @param model [Models::VmOperationResult] result model
75
+ # @return [Hash] hash representation
76
+ def to_hash(model)
77
+ if model.operation == :clone && model.resource
78
+ {
79
+ "vmid" => model.resource[:new_vmid],
80
+ "name" => model.resource[:name],
81
+ "node" => model.resource[:node] || model.vm&.node,
82
+ "status" => model.status_text,
83
+ "message" => model.message,
84
+ "task_upid" => model.task_upid || model.task&.upid
85
+ }
86
+ else
87
+ {
88
+ "vmid" => model.vm.vmid,
89
+ "name" => model.vm.name,
90
+ "node" => model.vm.node,
91
+ "status" => model.status_text,
92
+ "message" => model.message,
93
+ "task_upid" => model.task_upid || model.task&.upid
94
+ }
95
+ end
96
+ end
97
+
98
+ private
99
+
100
+ # Returns display name for VM.
101
+ #
102
+ # @param vm [Models::Vm] VM model
103
+ # @return [String] display name
104
+ def display_name(vm)
105
+ vm.name || "VM-#{vm.vmid}"
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Presenters
5
+ # Presenter for virtual disks (volumes) attached to VMs and containers.
6
+ #
7
+ # Defines column layout and formatting for table output.
8
+ # Standard columns show node, resource type, ID, name, storage, size, and format.
9
+ # Wide columns add volume ID, cache, discard, SSD, iothread, and backup flags.
10
+ #
11
+ # @example Using with formatter
12
+ # presenter = Volume.new
13
+ # formatter = Formatters::Table.new
14
+ # output = formatter.format(volumes, presenter)
15
+ #
16
+ # @see Pvectl::Models::Volume Volume model
17
+ # @see Pvectl::Formatters::Table Table formatter
18
+ #
19
+ class Volume < Base
20
+ # Returns column headers for standard table output.
21
+ #
22
+ # @return [Array<String>] column headers
23
+ def columns
24
+ %w[NODE RESOURCE ID NAME STORAGE SIZE FORMAT]
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[VOLUME-ID CACHE DISCARD SSD IOTHREAD BACKUP]
32
+ end
33
+
34
+ # Converts Volume model to table row values.
35
+ #
36
+ # @param model [Models::Volume] Volume model
37
+ # @param _context [Hash] optional context
38
+ # @return [Array<String>] row values matching columns order
39
+ def to_row(model, **_context)
40
+ @volume = model
41
+ [
42
+ volume.node || "-",
43
+ volume.resource_type || "-",
44
+ volume.resource_id&.to_s || "-",
45
+ volume.name || "-",
46
+ volume.storage || "-",
47
+ volume.size || "-",
48
+ volume.format || "-"
49
+ ]
50
+ end
51
+
52
+ # Returns additional values for wide output.
53
+ #
54
+ # @param model [Models::Volume] Volume model
55
+ # @param _context [Hash] optional context
56
+ # @return [Array<String>] extra values matching extra_columns order
57
+ def extra_values(model, **_context)
58
+ @volume = model
59
+ [
60
+ volume.volume_id || "-",
61
+ volume.cache || "-",
62
+ volume.discard || "-",
63
+ volume.ssd&.to_s || "-",
64
+ volume.iothread&.to_s || "-",
65
+ volume.backup&.to_s || "-"
66
+ ]
67
+ end
68
+
69
+ # Converts Volume model to hash for JSON/YAML output.
70
+ #
71
+ # @param model [Models::Volume] Volume model
72
+ # @return [Hash{String => untyped}] hash representation with string keys
73
+ def to_hash(model)
74
+ @volume = model
75
+ {
76
+ "name" => volume.name,
77
+ "storage" => volume.storage,
78
+ "volume_id" => volume.volume_id,
79
+ "volid" => volume.volid,
80
+ "size" => volume.size,
81
+ "format" => volume.format,
82
+ "resource_type" => volume.resource_type,
83
+ "resource_id" => volume.resource_id,
84
+ "node" => volume.node,
85
+ "content" => volume.content,
86
+ "cache" => volume.cache,
87
+ "discard" => volume.discard,
88
+ "ssd" => volume.ssd,
89
+ "iothread" => volume.iothread,
90
+ "backup" => volume.backup,
91
+ "mp" => volume.mp
92
+ }
93
+ end
94
+
95
+ # Returns detailed description for describe command output.
96
+ #
97
+ # @param model [Models::Volume] Volume model
98
+ # @return [Hash{String => Hash{String, String}}] nested hash with Volume Info section
99
+ def to_description(model)
100
+ @volume = model
101
+ { "Volume Info" => volume_info_section }
102
+ end
103
+
104
+ private
105
+
106
+ # @return [Models::Volume] the current volume being presented
107
+ attr_reader :volume
108
+
109
+ # Builds the Volume Info section hash.
110
+ # Optional fields are only included when they have values.
111
+ #
112
+ # @return [Hash{String => String}] volume info key-value pairs
113
+ def volume_info_section
114
+ info = {
115
+ "Name" => volume.name || "-",
116
+ "Storage" => volume.storage || "-",
117
+ "Volume ID" => volume.volume_id || "-",
118
+ "Full Volume ID" => volume.volid || "-",
119
+ "Size" => volume.size || "-",
120
+ "Format" => volume.format || "-",
121
+ "Resource Type" => volume.resource_type || "-",
122
+ "Resource ID" => volume.resource_id&.to_s || "-",
123
+ "Node" => volume.node || "-"
124
+ }
125
+ info["Content"] = volume.content if volume.content
126
+ info["Cache"] = volume.cache if volume.cache
127
+ info["Discard"] = volume.discard if volume.discard
128
+ info["SSD"] = volume.ssd if volume.ssd
129
+ info["IO Thread"] = volume.iothread if volume.iothread
130
+ info["Backup"] = volume.backup if volume.backup
131
+ info["Mount Point"] = volume.mp if volume.mp
132
+ info
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Presenters
5
+ # Presenter for volume operation results (set/edit).
6
+ #
7
+ # Formats VolumeOperationResult models for table/JSON/YAML output.
8
+ #
9
+ # @example Using with formatter
10
+ # presenter = VolumeOperationResult.new
11
+ # formatter = Formatters::Table.new
12
+ # output = formatter.format(results, presenter)
13
+ #
14
+ class VolumeOperationResult < OperationResult
15
+ # Returns column headers for standard table output.
16
+ #
17
+ # @return [Array<String>] column headers
18
+ def columns
19
+ %w[NODE RESOURCE ID DISK OPERATION STATUS MESSAGE]
20
+ end
21
+
22
+ # Converts result to table row values.
23
+ #
24
+ # @param model [Models::VolumeOperationResult] result model
25
+ # @param context [Hash] optional context
26
+ # @return [Array<String>] row values
27
+ def to_row(model, **_context)
28
+ vol = model.volume
29
+ [
30
+ vol&.node || "-",
31
+ vol&.resource_type || "-",
32
+ vol&.resource_id&.to_s || "-",
33
+ vol&.name || "-",
34
+ model.operation&.to_s || "-",
35
+ status_display(model),
36
+ model.message
37
+ ]
38
+ end
39
+
40
+ # Converts result to hash for JSON/YAML output.
41
+ #
42
+ # @param model [Models::VolumeOperationResult] result model
43
+ # @return [Hash] hash representation
44
+ def to_hash(model)
45
+ vol = model.volume
46
+ {
47
+ "node" => vol&.node,
48
+ "resource_type" => vol&.resource_type,
49
+ "resource_id" => vol&.resource_id,
50
+ "disk" => vol&.name,
51
+ "operation" => model.operation&.to_s,
52
+ "status" => model.status_text,
53
+ "message" => model.message
54
+ }
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Repositories
5
+ # Repository for Proxmox APT package management on cluster nodes.
6
+ #
7
+ # Wraps the `/nodes/{node}/apt/*` API endpoints. Provides:
8
+ # - listing pending package updates (GET /apt/update)
9
+ # - refreshing the package index (POST /apt/update — apt-get update)
10
+ # - reading per-package changelogs (GET /apt/changelog)
11
+ # - listing important Proxmox package versions (GET /apt/versions)
12
+ #
13
+ # @example Listing pending updates on a node
14
+ # repo = Apt.new(connection)
15
+ # updates = repo.pending("pve1")
16
+ # updates.each { |p| puts "#{p.package}: #{p.old_version} -> #{p.version}" }
17
+ #
18
+ # @example Triggering a package index refresh
19
+ # upid = repo.refresh("pve1", notify: false, quiet: true)
20
+ #
21
+ # @see Pvectl::Models::AptPackage AptPackage model
22
+ # @see Pvectl::Connection API connection
23
+ #
24
+ class Apt < Base
25
+ # Lists pending APT updates available on a node.
26
+ #
27
+ # @param node [String] node name
28
+ # @return [Array<Models::AptPackage>] pending package updates
29
+ def pending(node)
30
+ response = connection.client["nodes/#{node}/apt/update"].get
31
+ packages = unwrap(response)
32
+ packages.map { |data| build_model(data.merge(node: node)) }
33
+ rescue StandardError
34
+ []
35
+ end
36
+
37
+ # Refreshes the package index on a node (equivalent to apt-get update).
38
+ #
39
+ # Returns the Proxmox task UPID — the operation runs asynchronously.
40
+ #
41
+ # @param node [String] node name
42
+ # @param notify [Boolean] whether to send a notification about new packages
43
+ # @param quiet [Boolean] whether to suppress progress output
44
+ # @return [String] task UPID
45
+ def refresh(node, notify: false, quiet: false)
46
+ params = {}
47
+ params[:notify] = 1 if notify
48
+ params[:quiet] = 1 if quiet
49
+ response = connection.client["nodes/#{node}/apt/update"].post(params)
50
+ data = extract_data(response)
51
+ data.is_a?(String) ? data : data.to_s
52
+ end
53
+
54
+ # Fetches the changelog for a package on a node.
55
+ #
56
+ # @param node [String] node name
57
+ # @param package [String] package name
58
+ # @param version [String, nil] specific package version (optional)
59
+ # @return [String] changelog text (empty string on error)
60
+ def changelog(node, package, version: nil)
61
+ params = { name: package }
62
+ params[:version] = version if version
63
+ response = connection.client["nodes/#{node}/apt/changelog"].get(params: params)
64
+ data = extract_data(response)
65
+ data.is_a?(String) ? data : data.to_s
66
+ rescue StandardError
67
+ ""
68
+ end
69
+
70
+ # Lists important Proxmox package versions installed on a node.
71
+ #
72
+ # @param node [String] node name
73
+ # @return [Array<Models::AptPackage>] installed package versions
74
+ def versions(node)
75
+ response = connection.client["nodes/#{node}/apt/versions"].get
76
+ packages = unwrap(response)
77
+ packages.map { |data| build_model(data.merge(node: node)) }
78
+ rescue StandardError
79
+ []
80
+ end
81
+
82
+ protected
83
+
84
+ # Builds AptPackage model from API response data.
85
+ #
86
+ # @param data [Hash] API response hash
87
+ # @return [Models::AptPackage] AptPackage model instance
88
+ def build_model(data)
89
+ Models::AptPackage.new(data)
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,186 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+
5
+ module Pvectl
6
+ module Repositories
7
+ # Repository for backup operations in Proxmox.
8
+ #
9
+ # Handles listing, creating, deleting, and restoring backups
10
+ # via the Proxmox API (vzdump).
11
+ #
12
+ # @example Listing backups
13
+ # repo = Backup.new(connection)
14
+ # backups = repo.list(node: "pve1", storage: "local")
15
+ #
16
+ # @example Creating a backup
17
+ # upid = repo.create(100, "pve1", storage: "local", mode: "snapshot")
18
+ #
19
+ # @example Restoring a backup
20
+ # upid = repo.restore("local:backup/vzdump-qemu-100.vma.zst", "pve1", vmid: 200)
21
+ #
22
+ # @see Pvectl::Models::Backup Backup model
23
+ # @see Pvectl::Connection API connection
24
+ #
25
+ class Backup < Base
26
+ # Lists backups from storage.
27
+ #
28
+ # When node and storage are not specified, discovers all nodes and
29
+ # backup-capable storages automatically.
30
+ #
31
+ # @param vmid [Integer, nil] filter by VM ID
32
+ # @param storage [String, nil] storage name (default: all backup storages)
33
+ # @param node [String, nil] node name (default: all nodes)
34
+ # @return [Array<Models::Backup>] backup models
35
+ def list(vmid: nil, storage: nil, node: nil)
36
+ nodes = node ? [node] : list_nodes
37
+ storages_by_node = storage ? Hash[nodes.map { |n| [n, [storage]] }] : nil
38
+
39
+ backups = []
40
+ nodes.each do |n|
41
+ backup_storages = storages_by_node ? storages_by_node[n] : list_backup_storages(n)
42
+ backup_storages.each do |s|
43
+ backups.concat(list_from_storage(n, s, vmid: vmid))
44
+ end
45
+ end
46
+ backups
47
+ end
48
+
49
+ # Creates a backup using vzdump.
50
+ #
51
+ # @param vmid [Integer] VM/container ID
52
+ # @param node [String] node name
53
+ # @param storage [String] target storage
54
+ # @param mode [String] backup mode (snapshot, suspend, stop)
55
+ # @param compress [String] compression (zstd, gzip, lzo, 0)
56
+ # @param notes [String, nil] backup notes
57
+ # @param protected [Boolean] protect from deletion
58
+ # @return [String] task UPID
59
+ def create(vmid, node, storage:, mode: "snapshot", compress: "zstd", notes: nil, protected: false)
60
+ params = {
61
+ vmid: vmid,
62
+ storage: storage,
63
+ mode: mode,
64
+ compress: compress
65
+ }
66
+ params[:notes] = notes if notes
67
+ params[:protected] = 1 if protected
68
+
69
+ connection.client["nodes/#{node}/vzdump"].post(params)
70
+ end
71
+
72
+ # Deletes a backup.
73
+ #
74
+ # @param volid [String] full volume ID
75
+ # @param node [String] node name
76
+ # @return [String, nil] task UPID or nil
77
+ def delete(volid, node)
78
+ storage = parse_storage(volid)
79
+ encoded_volid = ERB::Util.url_encode(volid)
80
+ connection.client["nodes/#{node}/storage/#{storage}/content/#{encoded_volid}"].delete
81
+ end
82
+
83
+ # Restores a backup to a new or existing VM/container.
84
+ #
85
+ # @param volid [String] backup volume ID
86
+ # @param node [String] node name
87
+ # @param vmid [Integer] target VM ID
88
+ # @param storage [String, nil] target storage
89
+ # @param force [Boolean] overwrite existing VM
90
+ # @param start [Boolean] start after restore
91
+ # @param unique [Boolean] regenerate unique properties
92
+ # @return [String] task UPID
93
+ def restore(volid, node, vmid:, storage: nil, force: false, start: false, unique: false)
94
+ resource_type = detect_type_from_volid(volid)
95
+ endpoint = resource_type == :lxc ? "lxc" : "qemu"
96
+
97
+ params = {
98
+ archive: volid,
99
+ vmid: vmid
100
+ }
101
+ params[:storage] = storage if storage
102
+ params[:force] = 1 if force
103
+ params[:start] = 1 if start
104
+ params[:unique] = 1 if unique
105
+
106
+ connection.client["nodes/#{node}/#{endpoint}"].post(params)
107
+ end
108
+
109
+ private
110
+
111
+ # Lists all nodes in the cluster.
112
+ #
113
+ # @return [Array<String>] node names
114
+ def list_nodes
115
+ response = connection.client["nodes"].get
116
+ response.map { |n| n[:node] || n["node"] }
117
+ end
118
+
119
+ # Lists storages that support backup content on a node.
120
+ #
121
+ # @param node [String] node name
122
+ # @return [Array<String>] storage names with backup capability
123
+ def list_backup_storages(node)
124
+ response = connection.client["nodes/#{node}/storage"].get
125
+ response.select do |s|
126
+ content = s[:content] || s["content"] || ""
127
+ content.include?("backup")
128
+ end.map { |s| s[:storage] || s["storage"] }
129
+ end
130
+
131
+ # Lists backups from a specific storage on a node.
132
+ #
133
+ # @param node [String] node name
134
+ # @param storage [String] storage name
135
+ # @param vmid [Integer, nil] optional VM ID filter
136
+ # @return [Array<Models::Backup>] backup models
137
+ def list_from_storage(node, storage, vmid: nil)
138
+ response = connection.client["nodes/#{node}/storage/#{storage}/content"].get(params: { content: "backup" })
139
+
140
+ backups = response.map do |data|
141
+ build_backup_model(data, node, storage)
142
+ end
143
+
144
+ vmid ? backups.select { |b| b.vmid == vmid } : backups
145
+ end
146
+
147
+ # Builds a Backup model from API response data.
148
+ #
149
+ # @param data [Hash] API response hash
150
+ # @param node [String] node name
151
+ # @param storage [String] storage name
152
+ # @return [Models::Backup] backup model instance
153
+ def build_backup_model(data, node, storage)
154
+ Models::Backup.new(
155
+ volid: data[:volid] || data["volid"],
156
+ vmid: data[:vmid] || data["vmid"],
157
+ node: node,
158
+ storage: storage,
159
+ size: data[:size] || data["size"],
160
+ ctime: data[:ctime] || data["ctime"],
161
+ format: data[:format] || data["format"],
162
+ notes: data[:notes] || data["notes"],
163
+ protected: (data[:protected] || data["protected"]) == 1
164
+ )
165
+ end
166
+
167
+ # Extracts storage name from volid.
168
+ #
169
+ # @param volid [String] full volume identifier
170
+ # @return [String] storage name
171
+ def parse_storage(volid)
172
+ volid.split(":").first
173
+ end
174
+
175
+ # Detects resource type from volid pattern.
176
+ #
177
+ # @param volid [String] backup volume identifier
178
+ # @return [Symbol] :qemu or :lxc
179
+ def detect_type_from_volid(volid)
180
+ return :lxc if volid.include?("vzdump-lxc")
181
+
182
+ :qemu
183
+ end
184
+ end
185
+ end
186
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pvectl
4
+ module Repositories
5
+ # Abstract base class for repositories.
6
+ #
7
+ # Repositories encapsulate Proxmox API communication and are responsible
8
+ # for converting raw API data to domain models. Each repository handles
9
+ # one resource type (VMs, Containers, Nodes, etc.).
10
+ #
11
+ # @abstract Subclass and implement {#list}, {#get}, and {#build_model}.
12
+ #
13
+ # @example Implementing a repository
14
+ # class Vm < Base
15
+ # def list(node: nil)
16
+ # response = connection.client["cluster/resources"].get(params: { type: "vm" })
17
+ # response.map { |data| build_model(data) }
18
+ # end
19
+ #
20
+ # def get(vmid)
21
+ # list.find { |vm| vm.vmid == vmid.to_i }
22
+ # end
23
+ #
24
+ # protected
25
+ #
26
+ # def build_model(data)
27
+ # Models::Vm.new(data)
28
+ # end
29
+ # end
30
+ #
31
+ # @see Pvectl::Connection API connection wrapper
32
+ # @see Pvectl::Models::Base Model base class
33
+ #
34
+ class Base
35
+ # Creates repository with connection.
36
+ #
37
+ # @param connection [Connection] Proxmox API connection
38
+ def initialize(connection)
39
+ @connection = connection
40
+ end
41
+
42
+ # Lists all resources.
43
+ #
44
+ # @return [Array<Models::Base>] collection of models
45
+ # @raise [NotImplementedError] if not implemented by subclass
46
+ def list
47
+ raise NotImplementedError, "#{self.class}#list must be implemented"
48
+ end
49
+
50
+ # Gets a single resource by ID.
51
+ #
52
+ # @param id [String, Integer] resource identifier
53
+ # @return [Models::Base, nil] model or nil if not found
54
+ # @raise [NotImplementedError] if not implemented by subclass
55
+ def get(id)
56
+ raise NotImplementedError, "#{self.class}#get must be implemented"
57
+ end
58
+
59
+ protected
60
+
61
+ # @return [Connection] the API connection
62
+ attr_reader :connection
63
+
64
+ # Builds model from API response data.
65
+ #
66
+ # @param data [Hash] API response hash
67
+ # @return [Models::Base] model instance
68
+ # @raise [NotImplementedError] if not implemented by subclass
69
+ def build_model(data)
70
+ raise NotImplementedError, "#{self.class}#build_model must be implemented"
71
+ end
72
+
73
+ # Unwraps API response to array format.
74
+ # Handles: Array (passthrough), Hash with :data key, Hash without :data.
75
+ #
76
+ # @param response [Array, Hash, nil] API response
77
+ # @return [Array] unwrapped array
78
+ def unwrap(response)
79
+ case response
80
+ when Array then response
81
+ when Hash then response[:data] || response.to_a
82
+ when nil then []
83
+ else response.to_a
84
+ end
85
+ end
86
+
87
+ # Extracts data from hash response.
88
+ # If response has :data key, returns its value. Otherwise returns response.
89
+ #
90
+ # @param response [Hash, Object] API response
91
+ # @return [Hash, Object] extracted data
92
+ def extract_data(response)
93
+ return response unless response.is_a?(Hash)
94
+
95
+ response[:data] || response
96
+ end
97
+
98
+ # Creates model instances from API response.
99
+ #
100
+ # @param response [Array, Hash, nil] API response (will be unwrapped)
101
+ # @param model_class [Class] model class to instantiate
102
+ # @return [Array] array of model instances
103
+ def models_from(response, model_class)
104
+ return [] if response.nil?
105
+
106
+ unwrap(response).map { |data| model_class.new(data) }
107
+ end
108
+ end
109
+ end
110
+ end